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 , _editor_track_selection_change_without_scroll (false)
404 , cd_marker_bar_drag_rect (0)
405 , range_bar_drag_rect (0)
406 , transport_bar_drag_rect (0)
407 , transport_bar_range_rect (0)
408 , transport_bar_preroll_rect (0)
409 , transport_bar_postroll_rect (0)
410 , transport_loop_range_rect (0)
411 , transport_punch_range_rect (0)
412 , transport_punchin_line (0)
413 , transport_punchout_line (0)
414 , transport_preroll_rect (0)
415 , transport_postroll_rect (0)
417 , rubberband_rect (0)
423 , autoscroll_horizontal_allowed (false)
424 , autoscroll_vertical_allowed (false)
426 , autoscroll_widget (0)
427 , show_gain_after_trim (false)
428 , selection_op_cmd_depth (0)
429 , selection_op_history_it (0)
430 , no_save_instant (false)
432 , current_mixer_strip (0)
433 , show_editor_mixer_when_tracks_arrive (false)
434 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
435 , current_stepping_trackview (0)
436 , last_track_height_step_timestamp (0)
438 , entered_regionview (0)
439 , clear_entered_track (false)
440 , _edit_point (EditAtMouse)
441 , meters_running (false)
443 , _have_idled (false)
444 , resize_idle_id (-1)
445 , _pending_resize_amount (0)
446 , _pending_resize_view (0)
447 , _pending_locate_request (false)
448 , _pending_initial_locate (false)
452 , layering_order_editor (0)
453 , _last_cut_copy_source_track (0)
454 , _region_selection_change_updates_region_list (true)
456 , _following_mixer_selection (false)
457 , _control_point_toggled_on_press (false)
458 , _stepping_axis_view (0)
459 , quantize_dialog (0)
460 , _main_menu_disabler (0)
461 , myactions (X_("editor"))
463 /* we are a singleton */
465 PublicEditor::_instance = this;
469 last_event_time.tv_sec = 0;
470 last_event_time.tv_usec = 0;
472 selection_op_history.clear();
475 snap_type_strings = I18N (_snap_type_strings);
476 snap_mode_strings = I18N (_snap_mode_strings);
477 zoom_focus_strings = I18N (_zoom_focus_strings);
478 edit_mode_strings = I18N (_edit_mode_strings);
479 edit_point_strings = I18N (_edit_point_strings);
480 #ifdef USE_RUBBERBAND
481 rb_opt_strings = I18N (_rb_opt_strings);
485 build_edit_mode_menu();
486 build_zoom_focus_menu();
487 build_track_count_menu();
488 build_snap_mode_menu();
489 build_snap_type_menu();
490 build_edit_point_menu();
492 location_marker_color = UIConfiguration::instance().color ("location marker");
493 location_range_color = UIConfiguration::instance().color ("location range");
494 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
495 location_loop_color = UIConfiguration::instance().color ("location loop");
496 location_punch_color = UIConfiguration::instance().color ("location punch");
498 timebar_height = std::max (12., ceil (15. * UIConfiguration::instance().get_ui_scale()));
500 TimeAxisView::setup_sizes ();
501 ArdourMarker::setup_sizes (timebar_height);
502 TempoCurve::setup_sizes (timebar_height);
504 bbt_label.set_name ("EditorRulerLabel");
505 bbt_label.set_size_request (-1, (int)timebar_height);
506 bbt_label.set_alignment (1.0, 0.5);
507 bbt_label.set_padding (5,0);
509 bbt_label.set_no_show_all();
510 minsec_label.set_name ("EditorRulerLabel");
511 minsec_label.set_size_request (-1, (int)timebar_height);
512 minsec_label.set_alignment (1.0, 0.5);
513 minsec_label.set_padding (5,0);
514 minsec_label.hide ();
515 minsec_label.set_no_show_all();
516 timecode_label.set_name ("EditorRulerLabel");
517 timecode_label.set_size_request (-1, (int)timebar_height);
518 timecode_label.set_alignment (1.0, 0.5);
519 timecode_label.set_padding (5,0);
520 timecode_label.hide ();
521 timecode_label.set_no_show_all();
522 samples_label.set_name ("EditorRulerLabel");
523 samples_label.set_size_request (-1, (int)timebar_height);
524 samples_label.set_alignment (1.0, 0.5);
525 samples_label.set_padding (5,0);
526 samples_label.hide ();
527 samples_label.set_no_show_all();
529 tempo_label.set_name ("EditorRulerLabel");
530 tempo_label.set_size_request (-1, (int)timebar_height);
531 tempo_label.set_alignment (1.0, 0.5);
532 tempo_label.set_padding (5,0);
534 tempo_label.set_no_show_all();
536 meter_label.set_name ("EditorRulerLabel");
537 meter_label.set_size_request (-1, (int)timebar_height);
538 meter_label.set_alignment (1.0, 0.5);
539 meter_label.set_padding (5,0);
541 meter_label.set_no_show_all();
543 if (Profile->get_trx()) {
544 mark_label.set_text (_("Markers"));
546 mark_label.set_name ("EditorRulerLabel");
547 mark_label.set_size_request (-1, (int)timebar_height);
548 mark_label.set_alignment (1.0, 0.5);
549 mark_label.set_padding (5,0);
551 mark_label.set_no_show_all();
553 cd_mark_label.set_name ("EditorRulerLabel");
554 cd_mark_label.set_size_request (-1, (int)timebar_height);
555 cd_mark_label.set_alignment (1.0, 0.5);
556 cd_mark_label.set_padding (5,0);
557 cd_mark_label.hide();
558 cd_mark_label.set_no_show_all();
560 videotl_bar_height = 4;
561 videotl_label.set_name ("EditorRulerLabel");
562 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
563 videotl_label.set_alignment (1.0, 0.5);
564 videotl_label.set_padding (5,0);
565 videotl_label.hide();
566 videotl_label.set_no_show_all();
568 range_mark_label.set_name ("EditorRulerLabel");
569 range_mark_label.set_size_request (-1, (int)timebar_height);
570 range_mark_label.set_alignment (1.0, 0.5);
571 range_mark_label.set_padding (5,0);
572 range_mark_label.hide();
573 range_mark_label.set_no_show_all();
575 transport_mark_label.set_name ("EditorRulerLabel");
576 transport_mark_label.set_size_request (-1, (int)timebar_height);
577 transport_mark_label.set_alignment (1.0, 0.5);
578 transport_mark_label.set_padding (5,0);
579 transport_mark_label.hide();
580 transport_mark_label.set_no_show_all();
582 initialize_canvas ();
584 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
586 _summary = new EditorSummary (this);
588 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
590 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
592 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
593 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
595 edit_controls_vbox.set_spacing (0);
596 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
597 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
599 HBox* h = manage (new HBox);
600 _group_tabs = new EditorGroupTabs (this);
601 if (!ARDOUR::Profile->get_trx()) {
602 h->pack_start (*_group_tabs, PACK_SHRINK);
604 h->pack_start (edit_controls_vbox);
605 controls_layout.add (*h);
607 controls_layout.set_name ("EditControlsBase");
608 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
609 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
610 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
612 _cursors = new MouseCursors;
613 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
614 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
616 /* Push default cursor to ever-present bottom of cursor stack. */
617 push_canvas_cursor(_cursors->grabber);
619 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
621 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
622 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
623 pad_line_1->set_outline_color (0xFF0000FF);
629 edit_packer.set_col_spacings (0);
630 edit_packer.set_row_spacings (0);
631 edit_packer.set_homogeneous (false);
632 edit_packer.set_border_width (0);
633 edit_packer.set_name ("EditorWindow");
635 time_bars_event_box.add (time_bars_vbox);
636 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
637 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
639 /* labels for the time bars */
640 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
642 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
644 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
646 bottom_hbox.set_border_width (2);
647 bottom_hbox.set_spacing (3);
649 PresentationInfo::Change.connect (*this, MISSING_INVALIDATOR, boost::bind (&Editor::presentation_info_changed, this, _1), gui_context());
651 _route_groups = new EditorRouteGroups (this);
652 _routes = new EditorRoutes (this);
653 _regions = new EditorRegions (this);
654 _snapshots = new EditorSnapshots (this);
655 _locations = new EditorLocations (this);
656 _time_info_box = new TimeInfoBox ("EditorTimeInfo", true);
658 /* these are static location signals */
660 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
661 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
662 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
664 add_notebook_page (_("Regions"), _regions->widget ());
665 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
666 add_notebook_page (_("Snapshots"), _snapshots->widget ());
667 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
668 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
670 _the_notebook.set_show_tabs (true);
671 _the_notebook.set_scrollable (true);
672 _the_notebook.popup_disable ();
673 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
674 _the_notebook.show_all ();
676 _notebook_shrunk = false;
679 /* Pick up some settings we need to cache, early */
681 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
684 settings->get_property ("notebook-shrunk", _notebook_shrunk);
687 editor_summary_pane.set_check_divider_position (true);
688 editor_summary_pane.add (edit_packer);
690 Button* summary_arrow_left = manage (new Button);
691 summary_arrow_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
692 summary_arrow_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
693 summary_arrow_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
695 Button* summary_arrow_right = manage (new Button);
696 summary_arrow_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
697 summary_arrow_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
698 summary_arrow_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
700 VBox* summary_arrows_left = manage (new VBox);
701 summary_arrows_left->pack_start (*summary_arrow_left);
703 VBox* summary_arrows_right = manage (new VBox);
704 summary_arrows_right->pack_start (*summary_arrow_right);
706 Frame* summary_sample = manage (new Frame);
707 summary_sample->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
709 summary_sample->add (*_summary);
710 summary_sample->show ();
712 _summary_hbox.pack_start (*summary_arrows_left, false, false);
713 _summary_hbox.pack_start (*summary_sample, true, true);
714 _summary_hbox.pack_start (*summary_arrows_right, false, false);
716 if (!ARDOUR::Profile->get_trx()) {
717 editor_summary_pane.add (_summary_hbox);
720 edit_pane.set_check_divider_position (true);
721 edit_pane.add (editor_summary_pane);
722 if (!ARDOUR::Profile->get_trx()) {
723 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
724 _editor_list_vbox.pack_start (_the_notebook);
725 edit_pane.add (_editor_list_vbox);
726 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
729 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
730 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
733 if (!settings || !settings->get_property ("edit-horizontal-pane-pos", fract) || fract > 1.0) {
734 /* initial allocation is 90% to canvas, 10% to notebook */
737 edit_pane.set_divider (0, fract);
739 if (!settings || !settings->get_property ("edit-vertical-pane-pos", fract) || fract > 1.0) {
740 /* initial allocation is 90% to canvas, 10% to summary */
743 editor_summary_pane.set_divider (0, fract);
745 global_vpacker.set_spacing (2);
746 global_vpacker.set_border_width (0);
748 //the next three EventBoxes provide the ability for their child widgets to have a background color. That is all.
750 Gtk::EventBox* ebox = manage (new Gtk::EventBox); //a themeable box
751 ebox->set_name("EditorWindow");
752 ebox->add (toolbar_hbox);
754 Gtk::EventBox* epane_box = manage (new EventBoxExt); //a themeable box
755 epane_box->set_name("EditorWindow");
756 epane_box->add (edit_pane);
758 Gtk::EventBox* epane_box2 = manage (new EventBoxExt); //a themeable box
759 epane_box2->set_name("EditorWindow");
760 epane_box2->add (global_vpacker);
762 global_vpacker.pack_start (*ebox, false, false);
763 global_vpacker.pack_start (*epane_box, true, true);
764 global_hpacker.pack_start (*epane_box2, true, true);
766 /* need to show the "contents" widget so that notebook will show if tab is switched to
769 global_hpacker.show ();
771 /* register actions now so that set_state() can find them and set toggles/checks etc */
778 _playlist_selector = new PlaylistSelector();
779 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
781 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
785 nudge_forward_button.set_name ("nudge button");
786 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
788 nudge_backward_button.set_name ("nudge button");
789 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
791 fade_context_menu.set_name ("ArdourContextMenu");
793 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
795 /* allow external control surfaces/protocols to do various things */
797 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
798 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
799 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
800 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
801 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
802 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
803 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
804 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
805 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
806 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
807 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
808 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
809 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
810 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
812 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
813 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
814 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
815 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
816 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
818 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
822 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
824 /* problematic: has to return a value and thus cannot be x-thread */
826 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
828 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
829 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
831 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
833 _ignore_region_action = false;
834 _last_region_menu_was_main = false;
835 _popup_region_menu_item = 0;
837 _show_marker_lines = false;
839 /* Button bindings */
841 button_bindings = new Bindings ("editor-mouse");
843 XMLNode* node = button_settings();
845 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
846 button_bindings->load_operation (**i);
852 /* grab current parameter state */
853 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
854 UIConfiguration::instance().map_parameters (pc);
856 setup_fade_images ();
863 delete button_bindings;
865 delete _route_groups;
866 delete _track_canvas_viewport;
869 delete _verbose_cursor;
870 delete quantize_dialog;
876 delete _playlist_selector;
877 delete _time_info_box;
882 LuaInstance::destroy_instance ();
884 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
887 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_in_images.begin(); i != _xfade_in_images.end (); ++i) {
890 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_out_images.begin(); i != _xfade_out_images.end (); ++i) {
896 Editor::button_settings () const
898 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
899 XMLNode* node = find_named_node (*settings, X_("Buttons"));
902 node = new XMLNode (X_("Buttons"));
909 Editor::get_smart_mode () const
911 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
915 Editor::catch_vanishing_regionview (RegionView *rv)
917 /* note: the selection will take care of the vanishing
918 audioregionview by itself.
921 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
925 if (clicked_regionview == rv) {
926 clicked_regionview = 0;
929 if (entered_regionview == rv) {
930 set_entered_regionview (0);
933 if (!_all_region_actions_sensitized) {
934 sensitize_all_region_actions (true);
939 Editor::set_entered_regionview (RegionView* rv)
941 if (rv == entered_regionview) {
945 if (entered_regionview) {
946 entered_regionview->exited ();
949 entered_regionview = rv;
951 if (entered_regionview != 0) {
952 entered_regionview->entered ();
955 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
956 /* This RegionView entry might have changed what region actions
957 are allowed, so sensitize them all in case a key is pressed.
959 sensitize_all_region_actions (true);
964 Editor::set_entered_track (TimeAxisView* tav)
967 entered_track->exited ();
973 entered_track->entered ();
978 Editor::instant_save ()
980 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
985 _session->add_instant_xml(get_state());
987 Config->add_instant_xml(get_state());
992 Editor::control_vertical_zoom_in_all ()
994 tav_zoom_smooth (false, true);
998 Editor::control_vertical_zoom_out_all ()
1000 tav_zoom_smooth (true, true);
1004 Editor::control_vertical_zoom_in_selected ()
1006 tav_zoom_smooth (false, false);
1010 Editor::control_vertical_zoom_out_selected ()
1012 tav_zoom_smooth (true, false);
1016 Editor::control_view (uint32_t view)
1018 goto_visual_state (view);
1022 Editor::control_unselect ()
1024 selection->clear_tracks ();
1028 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1030 TimeAxisView* tav = time_axis_view_from_stripable (s);
1034 case Selection::Add:
1035 selection->add (tav);
1037 case Selection::Toggle:
1038 selection->toggle (tav);
1040 case Selection::Extend:
1042 case Selection::Set:
1043 selection->set (tav);
1047 selection->clear_tracks ();
1052 Editor::control_step_tracks_up ()
1054 scroll_tracks_up_line ();
1058 Editor::control_step_tracks_down ()
1060 scroll_tracks_down_line ();
1064 Editor::control_scroll (float fraction)
1066 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1072 double step = fraction * current_page_samples();
1075 _control_scroll_target is an optional<T>
1077 it acts like a pointer to an samplepos_t, with
1078 a operator conversion to boolean to check
1079 that it has a value could possibly use
1080 playhead_cursor->current_sample to store the
1081 value and a boolean in the class to know
1082 when it's out of date
1085 if (!_control_scroll_target) {
1086 _control_scroll_target = _session->transport_sample();
1087 _dragging_playhead = true;
1090 if ((fraction < 0.0f) && (*_control_scroll_target <= (samplepos_t) fabs(step))) {
1091 *_control_scroll_target = 0;
1092 } else if ((fraction > 0.0f) && (max_samplepos - *_control_scroll_target < step)) {
1093 *_control_scroll_target = max_samplepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1095 *_control_scroll_target += (samplepos_t) trunc (step);
1098 /* move visuals, we'll catch up with it later */
1100 playhead_cursor->set_position (*_control_scroll_target);
1101 UpdateAllTransportClocks (*_control_scroll_target);
1103 if (*_control_scroll_target > (current_page_samples() / 2)) {
1104 /* try to center PH in window */
1105 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1111 Now we do a timeout to actually bring the session to the right place
1112 according to the playhead. This is to avoid reading disk buffers on every
1113 call to control_scroll, which is driven by ScrollTimeline and therefore
1114 probably by a control surface wheel which can generate lots of events.
1116 /* cancel the existing timeout */
1118 control_scroll_connection.disconnect ();
1120 /* add the next timeout */
1122 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1126 Editor::deferred_control_scroll (samplepos_t /*target*/)
1128 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1129 // reset for next stream
1130 _control_scroll_target = boost::none;
1131 _dragging_playhead = false;
1136 Editor::access_action (const std::string& action_group, const std::string& action_item)
1142 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1145 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1153 Editor::set_toggleaction (const std::string& action_group, const std::string& action_item, bool s)
1155 ActionManager::set_toggleaction_state (action_group.c_str(), action_item.c_str(), s);
1159 Editor::on_realize ()
1163 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1164 start_lock_event_timing ();
1169 Editor::start_lock_event_timing ()
1171 /* check if we should lock the GUI every 30 seconds */
1173 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1177 Editor::generic_event_handler (GdkEvent* ev)
1180 case GDK_BUTTON_PRESS:
1181 case GDK_BUTTON_RELEASE:
1182 case GDK_MOTION_NOTIFY:
1184 case GDK_KEY_RELEASE:
1185 if (contents().is_mapped()) {
1186 gettimeofday (&last_event_time, 0);
1190 case GDK_LEAVE_NOTIFY:
1191 switch (ev->crossing.detail) {
1192 case GDK_NOTIFY_UNKNOWN:
1193 case GDK_NOTIFY_INFERIOR:
1194 case GDK_NOTIFY_ANCESTOR:
1196 case GDK_NOTIFY_VIRTUAL:
1197 case GDK_NOTIFY_NONLINEAR:
1198 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1199 /* leaving window, so reset focus, thus ending any and
1200 all text entry operations.
1202 ARDOUR_UI::instance()->reset_focus (&contents());
1215 Editor::lock_timeout_callback ()
1217 struct timeval now, delta;
1219 gettimeofday (&now, 0);
1221 timersub (&now, &last_event_time, &delta);
1223 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1225 /* don't call again. Returning false will effectively
1226 disconnect us from the timer callback.
1228 unlock() will call start_lock_event_timing() to get things
1238 Editor::map_position_change (samplepos_t sample)
1240 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, sample)
1242 if (_session == 0) {
1246 if (_follow_playhead) {
1247 center_screen (sample);
1250 playhead_cursor->set_position (sample);
1254 Editor::center_screen (samplepos_t sample)
1256 samplecnt_t const page = _visible_canvas_width * samples_per_pixel;
1258 /* if we're off the page, then scroll.
1261 if (sample < _leftmost_sample || sample >= _leftmost_sample + page) {
1262 center_screen_internal (sample, page);
1267 Editor::center_screen_internal (samplepos_t sample, float page)
1271 if (sample > page) {
1272 sample -= (samplepos_t) page;
1277 reset_x_origin (sample);
1282 Editor::update_title ()
1284 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1286 if (!own_window()) {
1291 bool dirty = _session->dirty();
1293 string session_name;
1295 if (_session->snap_name() != _session->name()) {
1296 session_name = _session->snap_name();
1298 session_name = _session->name();
1302 session_name = "*" + session_name;
1305 WindowTitle title(session_name);
1306 title += S_("Window|Editor");
1307 title += Glib::get_application_name();
1308 own_window()->set_title (title.get_string());
1310 /* ::session_going_away() will have taken care of it */
1315 Editor::set_session (Session *t)
1317 SessionHandlePtr::set_session (t);
1323 //initialize _leftmost_sample to the extents of the session
1324 //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
1325 _leftmost_sample = session_gui_extents().first;
1327 _playlist_selector->set_session (_session);
1328 nudge_clock->set_session (_session);
1329 _summary->set_session (_session);
1330 _group_tabs->set_session (_session);
1331 _route_groups->set_session (_session);
1332 _regions->set_session (_session);
1333 _snapshots->set_session (_session);
1334 _routes->set_session (_session);
1335 _locations->set_session (_session);
1336 _time_info_box->set_session (_session);
1338 if (rhythm_ferret) {
1339 rhythm_ferret->set_session (_session);
1342 if (analysis_window) {
1343 analysis_window->set_session (_session);
1347 sfbrowser->set_session (_session);
1350 compute_fixed_ruler_scale ();
1352 /* Make sure we have auto loop and auto punch ranges */
1354 Location* loc = _session->locations()->auto_loop_location();
1356 loc->set_name (_("Loop"));
1359 loc = _session->locations()->auto_punch_location();
1362 loc->set_name (_("Punch"));
1365 refresh_location_display ();
1367 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1368 the selected Marker; this needs the LocationMarker list to be available.
1370 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1371 set_state (*node, Stateful::loading_state_version);
1373 /* catch up on selection state, etc. */
1376 sc.add (Properties::selected);
1377 presentation_info_changed (sc);
1379 /* catch up with the playhead */
1381 _session->request_locate (playhead_cursor->current_sample ());
1382 _pending_initial_locate = true;
1386 /* These signals can all be emitted by a non-GUI thread. Therefore the
1387 handlers for them must not attempt to directly interact with the GUI,
1388 but use PBD::Signal<T>::connect() which accepts an event loop
1389 ("context") where the handler will be asked to run.
1392 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1393 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1394 _session->TransportLooped.connect (_session_connections, invalidator (*this), boost::bind (&Editor::transport_looped, this), gui_context());
1395 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1396 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1397 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1398 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1399 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1400 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1401 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1402 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1403 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1404 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1405 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1406 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1407 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1409 playhead_cursor->show ();
1411 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1412 Config->map_parameters (pc);
1413 _session->config.map_parameters (pc);
1415 restore_ruler_visibility ();
1416 //tempo_map_changed (PropertyChange (0));
1417 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1419 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1420 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1423 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1424 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1427 switch (_snap_type) {
1428 case SnapToRegionStart:
1429 case SnapToRegionEnd:
1430 case SnapToRegionSync:
1431 case SnapToRegionBoundary:
1432 build_region_boundary_cache ();
1439 /* register for undo history */
1440 _session->register_with_memento_command_factory(id(), this);
1441 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1443 LuaInstance::instance()->set_session(_session);
1445 start_updating_meters ();
1449 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1451 using namespace Menu_Helpers;
1453 void (Editor::*emf)(FadeShape);
1454 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1457 images = &_xfade_in_images;
1458 emf = &Editor::set_fade_in_shape;
1460 images = &_xfade_out_images;
1461 emf = &Editor::set_fade_out_shape;
1466 _("Linear (for highly correlated material)"),
1467 *(*images)[FadeLinear],
1468 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1472 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1476 _("Constant power"),
1477 *(*images)[FadeConstantPower],
1478 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1481 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1486 *(*images)[FadeSymmetric],
1487 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1491 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1496 *(*images)[FadeSlow],
1497 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1500 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1505 *(*images)[FadeFast],
1506 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1509 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1512 /** Pop up a context menu for when the user clicks on a start crossfade */
1514 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1516 using namespace Menu_Helpers;
1517 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1522 MenuList& items (xfade_in_context_menu.items());
1525 if (arv->audio_region()->fade_in_active()) {
1526 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1528 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1531 items.push_back (SeparatorElem());
1532 fill_xfade_menu (items, true);
1534 xfade_in_context_menu.popup (button, time);
1537 /** Pop up a context menu for when the user clicks on an end crossfade */
1539 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1541 using namespace Menu_Helpers;
1542 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1547 MenuList& items (xfade_out_context_menu.items());
1550 if (arv->audio_region()->fade_out_active()) {
1551 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1553 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1556 items.push_back (SeparatorElem());
1557 fill_xfade_menu (items, false);
1559 xfade_out_context_menu.popup (button, time);
1563 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1565 using namespace Menu_Helpers;
1566 Menu* (Editor::*build_menu_function)();
1569 switch (item_type) {
1571 case RegionViewName:
1572 case RegionViewNameHighlight:
1573 case LeftFrameHandle:
1574 case RightFrameHandle:
1575 if (with_selection) {
1576 build_menu_function = &Editor::build_track_selection_context_menu;
1578 build_menu_function = &Editor::build_track_region_context_menu;
1583 if (with_selection) {
1584 build_menu_function = &Editor::build_track_selection_context_menu;
1586 build_menu_function = &Editor::build_track_context_menu;
1591 if (clicked_routeview->track()) {
1592 build_menu_function = &Editor::build_track_context_menu;
1594 build_menu_function = &Editor::build_track_bus_context_menu;
1599 /* probably shouldn't happen but if it does, we don't care */
1603 menu = (this->*build_menu_function)();
1604 menu->set_name ("ArdourContextMenu");
1606 /* now handle specific situations */
1608 switch (item_type) {
1610 case RegionViewName:
1611 case RegionViewNameHighlight:
1612 case LeftFrameHandle:
1613 case RightFrameHandle:
1614 if (!with_selection) {
1615 if (region_edit_menu_split_item) {
1616 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1617 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1619 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1622 if (region_edit_menu_split_multichannel_item) {
1623 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1624 region_edit_menu_split_multichannel_item->set_sensitive (true);
1626 region_edit_menu_split_multichannel_item->set_sensitive (false);
1639 /* probably shouldn't happen but if it does, we don't care */
1643 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1645 /* Bounce to disk */
1647 using namespace Menu_Helpers;
1648 MenuList& edit_items = menu->items();
1650 edit_items.push_back (SeparatorElem());
1652 switch (clicked_routeview->audio_track()->freeze_state()) {
1653 case AudioTrack::NoFreeze:
1654 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1657 case AudioTrack::Frozen:
1658 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1661 case AudioTrack::UnFrozen:
1662 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1668 if (item_type == StreamItem && clicked_routeview) {
1669 clicked_routeview->build_underlay_menu(menu);
1672 /* When the region menu is opened, we setup the actions so that they look right
1675 sensitize_the_right_region_actions (false);
1676 _last_region_menu_was_main = false;
1678 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1679 menu->popup (button, time);
1683 Editor::build_track_context_menu ()
1685 using namespace Menu_Helpers;
1687 MenuList& edit_items = track_context_menu.items();
1690 add_dstream_context_items (edit_items);
1691 return &track_context_menu;
1695 Editor::build_track_bus_context_menu ()
1697 using namespace Menu_Helpers;
1699 MenuList& edit_items = track_context_menu.items();
1702 add_bus_context_items (edit_items);
1703 return &track_context_menu;
1707 Editor::build_track_region_context_menu ()
1709 using namespace Menu_Helpers;
1710 MenuList& edit_items = track_region_context_menu.items();
1713 /* we've just cleared the track region context menu, so the menu that these
1714 two items were on will have disappeared; stop them dangling.
1716 region_edit_menu_split_item = 0;
1717 region_edit_menu_split_multichannel_item = 0;
1719 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1722 boost::shared_ptr<Track> tr;
1723 boost::shared_ptr<Playlist> pl;
1725 if ((tr = rtv->track())) {
1726 add_region_context_items (edit_items, tr);
1730 add_dstream_context_items (edit_items);
1732 return &track_region_context_menu;
1736 Editor::loudness_analyze_region_selection ()
1741 Selection& s (PublicEditor::instance ().get_selection ());
1742 RegionSelection ars = s.regions;
1743 ARDOUR::AnalysisGraph ag (_session);
1744 samplecnt_t total_work = 0;
1746 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1747 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1751 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1754 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1755 total_work += arv->region ()->length ();
1758 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1760 ag.set_total_samples (total_work);
1761 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1764 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1765 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1769 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1773 ag.analyze_region (ar);
1776 if (!ag.canceled ()) {
1777 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1783 Editor::loudness_analyze_range_selection ()
1788 Selection& s (PublicEditor::instance ().get_selection ());
1789 TimeSelection ts = s.time;
1790 ARDOUR::AnalysisGraph ag (_session);
1791 samplecnt_t total_work = 0;
1793 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1794 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1798 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1802 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1803 total_work += j->length ();
1807 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1809 ag.set_total_samples (total_work);
1810 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1813 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1814 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1818 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1822 ag.analyze_range (rui->route (), pl, ts);
1825 if (!ag.canceled ()) {
1826 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1832 Editor::spectral_analyze_region_selection ()
1834 if (analysis_window == 0) {
1835 analysis_window = new AnalysisWindow();
1838 analysis_window->set_session(_session);
1840 analysis_window->show_all();
1843 analysis_window->set_regionmode();
1844 analysis_window->analyze();
1846 analysis_window->present();
1850 Editor::spectral_analyze_range_selection()
1852 if (analysis_window == 0) {
1853 analysis_window = new AnalysisWindow();
1856 analysis_window->set_session(_session);
1858 analysis_window->show_all();
1861 analysis_window->set_rangemode();
1862 analysis_window->analyze();
1864 analysis_window->present();
1868 Editor::build_track_selection_context_menu ()
1870 using namespace Menu_Helpers;
1871 MenuList& edit_items = track_selection_context_menu.items();
1872 edit_items.clear ();
1874 add_selection_context_items (edit_items);
1875 // edit_items.push_back (SeparatorElem());
1876 // add_dstream_context_items (edit_items);
1878 return &track_selection_context_menu;
1882 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1884 using namespace Menu_Helpers;
1886 /* OK, stick the region submenu at the top of the list, and then add
1890 RegionSelection rs = get_regions_from_selection_and_entered ();
1892 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1894 if (_popup_region_menu_item == 0) {
1895 _popup_region_menu_item = new MenuItem (menu_item_name, false);
1896 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1897 _popup_region_menu_item->show ();
1899 _popup_region_menu_item->set_label (menu_item_name);
1902 /* No layering allowed in later is higher layering model */
1903 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1904 if (act && Config->get_layer_model() == LaterHigher) {
1905 act->set_sensitive (false);
1907 act->set_sensitive (true);
1910 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1912 edit_items.push_back (*_popup_region_menu_item);
1913 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1914 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1916 edit_items.push_back (SeparatorElem());
1919 /** Add context menu items relevant to selection ranges.
1920 * @param edit_items List to add the items to.
1923 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1925 using namespace Menu_Helpers;
1927 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1928 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1930 edit_items.push_back (SeparatorElem());
1931 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1933 edit_items.push_back (SeparatorElem());
1934 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1935 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1937 edit_items.push_back (SeparatorElem());
1939 edit_items.push_back (
1941 _("Move Range Start to Previous Region Boundary"),
1942 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1946 edit_items.push_back (
1948 _("Move Range Start to Next Region Boundary"),
1949 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1953 edit_items.push_back (
1955 _("Move Range End to Previous Region Boundary"),
1956 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1960 edit_items.push_back (
1962 _("Move Range End to Next Region Boundary"),
1963 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1967 edit_items.push_back (SeparatorElem());
1968 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1969 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1971 edit_items.push_back (SeparatorElem());
1972 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1974 edit_items.push_back (SeparatorElem());
1975 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1976 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1977 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1979 edit_items.push_back (SeparatorElem());
1980 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1982 edit_items.push_back (SeparatorElem());
1983 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1984 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1986 edit_items.push_back (SeparatorElem());
1987 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1988 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1989 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1990 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1991 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1992 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1993 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1999 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2001 using namespace Menu_Helpers;
2005 Menu *play_menu = manage (new Menu);
2006 MenuList& play_items = play_menu->items();
2007 play_menu->set_name ("ArdourContextMenu");
2009 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2010 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2011 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2012 play_items.push_back (SeparatorElem());
2013 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2015 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2019 Menu *select_menu = manage (new Menu);
2020 MenuList& select_items = select_menu->items();
2021 select_menu->set_name ("ArdourContextMenu");
2023 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2024 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2025 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2026 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2027 select_items.push_back (SeparatorElem());
2028 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2029 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2030 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2031 select_items.push_back (SeparatorElem());
2032 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2033 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2034 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2035 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2036 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2037 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2038 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2040 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2044 Menu *cutnpaste_menu = manage (new Menu);
2045 MenuList& cutnpaste_items = cutnpaste_menu->items();
2046 cutnpaste_menu->set_name ("ArdourContextMenu");
2048 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2049 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2050 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2052 cutnpaste_items.push_back (SeparatorElem());
2054 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2055 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2057 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2059 /* Adding new material */
2061 edit_items.push_back (SeparatorElem());
2062 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2063 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2067 Menu *nudge_menu = manage (new Menu());
2068 MenuList& nudge_items = nudge_menu->items();
2069 nudge_menu->set_name ("ArdourContextMenu");
2071 edit_items.push_back (SeparatorElem());
2072 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2073 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2074 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2075 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2077 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2081 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2083 using namespace Menu_Helpers;
2087 Menu *play_menu = manage (new Menu);
2088 MenuList& play_items = play_menu->items();
2089 play_menu->set_name ("ArdourContextMenu");
2091 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2092 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2093 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2097 Menu *select_menu = manage (new Menu);
2098 MenuList& select_items = select_menu->items();
2099 select_menu->set_name ("ArdourContextMenu");
2101 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2102 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2103 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2104 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2105 select_items.push_back (SeparatorElem());
2106 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2107 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2108 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2109 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2111 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2115 Menu *cutnpaste_menu = manage (new Menu);
2116 MenuList& cutnpaste_items = cutnpaste_menu->items();
2117 cutnpaste_menu->set_name ("ArdourContextMenu");
2119 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2120 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2121 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2123 Menu *nudge_menu = manage (new Menu());
2124 MenuList& nudge_items = nudge_menu->items();
2125 nudge_menu->set_name ("ArdourContextMenu");
2127 edit_items.push_back (SeparatorElem());
2128 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2129 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2130 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2131 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2133 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2137 Editor::snap_type() const
2143 Editor::snap_musical() const
2145 switch (_snap_type) {
2146 case SnapToBeatDiv128:
2147 case SnapToBeatDiv64:
2148 case SnapToBeatDiv32:
2149 case SnapToBeatDiv28:
2150 case SnapToBeatDiv24:
2151 case SnapToBeatDiv20:
2152 case SnapToBeatDiv16:
2153 case SnapToBeatDiv14:
2154 case SnapToBeatDiv12:
2155 case SnapToBeatDiv10:
2156 case SnapToBeatDiv8:
2157 case SnapToBeatDiv7:
2158 case SnapToBeatDiv6:
2159 case SnapToBeatDiv5:
2160 case SnapToBeatDiv4:
2161 case SnapToBeatDiv3:
2162 case SnapToBeatDiv2:
2174 Editor::snap_mode() const
2180 Editor::set_snap_to (SnapType st)
2182 unsigned int snap_ind = (unsigned int)st;
2184 if (internal_editing()) {
2185 internal_snap_type = st;
2187 pre_internal_snap_type = st;
2192 if (snap_ind > snap_type_strings.size() - 1) {
2194 _snap_type = (SnapType)snap_ind;
2197 string str = snap_type_strings[snap_ind];
2199 if (str != snap_type_selector.get_text()) {
2200 snap_type_selector.set_text (str);
2205 switch (_snap_type) {
2206 case SnapToBeatDiv128:
2207 case SnapToBeatDiv64:
2208 case SnapToBeatDiv32:
2209 case SnapToBeatDiv28:
2210 case SnapToBeatDiv24:
2211 case SnapToBeatDiv20:
2212 case SnapToBeatDiv16:
2213 case SnapToBeatDiv14:
2214 case SnapToBeatDiv12:
2215 case SnapToBeatDiv10:
2216 case SnapToBeatDiv8:
2217 case SnapToBeatDiv7:
2218 case SnapToBeatDiv6:
2219 case SnapToBeatDiv5:
2220 case SnapToBeatDiv4:
2221 case SnapToBeatDiv3:
2222 case SnapToBeatDiv2: {
2223 compute_bbt_ruler_scale (_leftmost_sample, _leftmost_sample + current_page_samples());
2224 update_tempo_based_rulers ();
2228 case SnapToRegionStart:
2229 case SnapToRegionEnd:
2230 case SnapToRegionSync:
2231 case SnapToRegionBoundary:
2232 build_region_boundary_cache ();
2240 redisplay_tempo (false);
2242 SnapChanged (); /* EMIT SIGNAL */
2246 Editor::set_snap_mode (SnapMode mode)
2248 string str = snap_mode_strings[(int)mode];
2250 if (internal_editing()) {
2251 internal_snap_mode = mode;
2253 pre_internal_snap_mode = mode;
2258 if (str != snap_mode_selector.get_text ()) {
2259 snap_mode_selector.set_text (str);
2266 Editor::set_edit_point_preference (EditPoint ep, bool force)
2268 bool changed = (_edit_point != ep);
2271 if (Profile->get_mixbus())
2272 if (ep == EditAtSelectedMarker)
2273 ep = EditAtPlayhead;
2275 string str = edit_point_strings[(int)ep];
2276 if (str != edit_point_selector.get_text ()) {
2277 edit_point_selector.set_text (str);
2280 update_all_enter_cursors();
2282 if (!force && !changed) {
2286 const char* action=NULL;
2288 switch (_edit_point) {
2289 case EditAtPlayhead:
2290 action = "edit-at-playhead";
2292 case EditAtSelectedMarker:
2293 action = "edit-at-marker";
2296 action = "edit-at-mouse";
2300 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2302 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2306 bool in_track_canvas;
2308 if (!mouse_sample (foo, in_track_canvas)) {
2309 in_track_canvas = false;
2312 reset_canvas_action_sensitivity (in_track_canvas);
2313 sensitize_the_right_region_actions (false);
2319 Editor::set_state (const XMLNode& node, int version)
2322 PBD::Unwinder<bool> nsi (no_save_instant, true);
2325 Tabbable::set_state (node, version);
2328 if (_session && node.get_property ("playhead", ph_pos)) {
2330 playhead_cursor->set_position (ph_pos);
2332 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2333 playhead_cursor->set_position (0);
2336 playhead_cursor->set_position (0);
2339 node.get_property ("mixer-width", editor_mixer_strip_width);
2341 node.get_property ("zoom-focus", zoom_focus);
2342 zoom_focus_selection_done (zoom_focus);
2345 if (node.get_property ("zoom", z)) {
2346 /* older versions of ardour used floating point samples_per_pixel */
2347 reset_zoom (llrintf (z));
2349 reset_zoom (samples_per_pixel);
2353 if (node.get_property ("visible-track-count", cnt)) {
2354 set_visible_track_count (cnt);
2358 if (!node.get_property ("snap-to", snap_type)) {
2359 snap_type = _snap_type;
2361 set_snap_to (snap_type);
2364 if (node.get_property ("snap-mode", sm)) {
2365 snap_mode_selection_done(sm);
2366 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2367 * snap_mode_selection_done() will only mark an already active item as active
2368 * which does not trigger set_text().
2372 set_snap_mode (_snap_mode);
2375 node.get_property ("internal-snap-to", internal_snap_type);
2376 node.get_property ("internal-snap-mode", internal_snap_mode);
2377 node.get_property ("pre-internal-snap-to", pre_internal_snap_type);
2378 node.get_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2381 if (node.get_property ("mouse-mode", mm_str)) {
2382 MouseMode m = str2mousemode(mm_str);
2383 set_mouse_mode (m, true);
2385 set_mouse_mode (MouseObject, true);
2389 if (node.get_property ("left-frame", lf_pos)) {
2393 reset_x_origin (lf_pos);
2397 if (node.get_property ("y-origin", y_origin)) {
2398 reset_y_origin (y_origin);
2401 if (node.get_property ("join-object-range", yn)) {
2402 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2404 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2405 tact->set_active (!yn);
2406 tact->set_active (yn);
2408 set_mouse_mode(mouse_mode, true);
2412 if (node.get_property ("edit-point", ep)) {
2413 set_edit_point_preference (ep, true);
2415 set_edit_point_preference (_edit_point);
2418 node.get_property ("show-measures", _show_measures);
2420 if (node.get_property ("follow-playhead", yn)) {
2421 set_follow_playhead (yn);
2424 if (node.get_property ("stationary-playhead", yn)) {
2425 set_stationary_playhead (yn);
2428 RegionListSortType sort_type;
2429 if (node.get_property ("region-list-sort-type", sort_type)) {
2430 _regions->reset_sort_type (sort_type, true);
2433 if (node.get_property ("show-editor-mixer", yn)) {
2435 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2438 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2440 /* do it twice to force the change */
2442 tact->set_active (!yn);
2443 tact->set_active (yn);
2446 if (node.get_property ("show-editor-list", yn)) {
2448 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2451 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2453 /* do it twice to force the change */
2455 tact->set_active (!yn);
2456 tact->set_active (yn);
2460 if (node.get_property (X_("editor-list-page"), el_page)) {
2461 _the_notebook.set_current_page (el_page);
2464 if (node.get_property (X_("show-marker-lines"), yn)) {
2465 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2467 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2469 tact->set_active (!yn);
2470 tact->set_active (yn);
2473 XMLNodeList children = node.children ();
2474 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2475 selection->set_state (**i, Stateful::current_state_version);
2476 _regions->set_state (**i);
2477 _locations->set_state (**i);
2480 if (node.get_property ("maximised", yn)) {
2481 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2483 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2484 bool fs = tact && tact->get_active();
2486 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2490 samplepos_t nudge_clock_value;
2491 if (node.get_property ("nudge-clock-value", nudge_clock_value)) {
2492 nudge_clock->set (nudge_clock_value);
2494 nudge_clock->set_mode (AudioClock::Timecode);
2495 nudge_clock->set (_session->sample_rate() * 5, true);
2500 * Not all properties may have been in XML, but
2501 * those that are linked to a private variable may need changing
2505 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2507 yn = _show_measures;
2508 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2509 /* do it twice to force the change */
2510 tact->set_active (!yn);
2511 tact->set_active (yn);
2514 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2515 yn = _follow_playhead;
2517 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2518 if (tact->get_active() != yn) {
2519 tact->set_active (yn);
2523 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2524 yn = _stationary_playhead;
2526 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2527 if (tact->get_active() != yn) {
2528 tact->set_active (yn);
2533 return LuaInstance::instance()->set_state(node);
2537 Editor::get_state ()
2539 XMLNode* node = new XMLNode (X_("Editor"));
2541 node->set_property ("id", id().to_s ());
2543 node->add_child_nocopy (Tabbable::get_state());
2545 node->set_property("edit-horizontal-pane-pos", edit_pane.get_divider ());
2546 node->set_property("notebook-shrunk", _notebook_shrunk);
2547 node->set_property("edit-vertical-pane-pos", editor_summary_pane.get_divider());
2549 maybe_add_mixer_strip_width (*node);
2551 node->set_property ("zoom-focus", zoom_focus);
2553 node->set_property ("zoom", samples_per_pixel);
2554 node->set_property ("snap-to", _snap_type);
2555 node->set_property ("snap-mode", _snap_mode);
2556 node->set_property ("internal-snap-to", internal_snap_type);
2557 node->set_property ("internal-snap-mode", internal_snap_mode);
2558 node->set_property ("pre-internal-snap-to", pre_internal_snap_type);
2559 node->set_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2560 node->set_property ("edit-point", _edit_point);
2561 node->set_property ("visible-track-count", _visible_track_count);
2563 node->set_property ("playhead", playhead_cursor->current_sample ());
2564 node->set_property ("left-frame", _leftmost_sample);
2565 node->set_property ("y-origin", vertical_adjustment.get_value ());
2567 node->set_property ("show-measures", _show_measures);
2568 node->set_property ("maximised", _maximised);
2569 node->set_property ("follow-playhead", _follow_playhead);
2570 node->set_property ("stationary-playhead", _stationary_playhead);
2571 node->set_property ("region-list-sort-type", _regions->sort_type ());
2572 node->set_property ("mouse-mode", mouse_mode);
2573 node->set_property ("join-object-range", smart_mode_action->get_active ());
2575 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2577 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2578 node->set_property (X_("show-editor-mixer"), tact->get_active());
2581 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2583 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2584 node->set_property (X_("show-editor-list"), tact->get_active());
2587 node->set_property (X_("editor-list-page"), _the_notebook.get_current_page ());
2589 if (button_bindings) {
2590 XMLNode* bb = new XMLNode (X_("Buttons"));
2591 button_bindings->save (*bb);
2592 node->add_child_nocopy (*bb);
2595 node->set_property (X_("show-marker-lines"), _show_marker_lines);
2597 node->add_child_nocopy (selection->get_state ());
2598 node->add_child_nocopy (_regions->get_state ());
2600 node->set_property ("nudge-clock-value", nudge_clock->current_duration());
2602 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2603 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2604 node->add_child_nocopy (_locations->get_state ());
2609 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2610 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2612 * @return pair: TimeAxisView that y is over, layer index.
2614 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2615 * in stacked or expanded region display mode, otherwise 0.
2617 std::pair<TimeAxisView *, double>
2618 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2620 if (!trackview_relative_offset) {
2621 y -= _trackview_group->canvas_origin().y;
2625 return std::make_pair ( (TimeAxisView *) 0, 0);
2628 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2630 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2637 return std::make_pair ( (TimeAxisView *) 0, 0);
2640 /** Snap a position to the grid, if appropriate, taking into account current
2641 * grid settings and also the state of any snap modifier keys that may be pressed.
2642 * @param start Position to snap.
2643 * @param event Event to get current key modifier information from, or 0.
2646 Editor::snap_to_with_modifier (MusicSample& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2648 if (!_session || !event) {
2652 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2653 if (_snap_mode == SnapOff) {
2654 snap_to_internal (start, direction, for_mark);
2656 start.set (start.sample, 0);
2659 if (_snap_mode != SnapOff) {
2660 snap_to_internal (start, direction, for_mark);
2661 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2662 /* SnapOff, but we pressed the snap_delta modifier */
2663 snap_to_internal (start, direction, for_mark);
2665 start.set (start.sample, 0);
2671 Editor::snap_to (MusicSample& start, RoundMode direction, bool for_mark, bool ensure_snap)
2673 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2674 start.set (start.sample, 0);
2678 snap_to_internal (start, direction, for_mark, ensure_snap);
2682 Editor::timecode_snap_to_internal (MusicSample& pos, RoundMode direction, bool /*for_mark*/)
2684 samplepos_t start = pos.sample;
2685 const samplepos_t one_timecode_second = (samplepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2686 samplepos_t one_timecode_minute = (samplepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2688 switch (_snap_type) {
2689 case SnapToTimecodeFrame:
2690 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2691 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2692 /* start is already on a whole timecode frame, do nothing */
2693 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2694 start = (samplepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2696 start = (samplepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2700 case SnapToTimecodeSeconds:
2701 if (_session->config.get_timecode_offset_negative()) {
2702 start += _session->config.get_timecode_offset ();
2704 start -= _session->config.get_timecode_offset ();
2706 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2707 (start % one_timecode_second == 0)) {
2708 /* start is already on a whole second, do nothing */
2709 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2710 start = (samplepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2712 start = (samplepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2715 if (_session->config.get_timecode_offset_negative()) {
2716 start -= _session->config.get_timecode_offset ();
2718 start += _session->config.get_timecode_offset ();
2722 case SnapToTimecodeMinutes:
2723 if (_session->config.get_timecode_offset_negative()) {
2724 start += _session->config.get_timecode_offset ();
2726 start -= _session->config.get_timecode_offset ();
2728 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2729 (start % one_timecode_minute == 0)) {
2730 /* start is already on a whole minute, do nothing */
2731 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2732 start = (samplepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2734 start = (samplepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2736 if (_session->config.get_timecode_offset_negative()) {
2737 start -= _session->config.get_timecode_offset ();
2739 start += _session->config.get_timecode_offset ();
2743 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2744 abort(); /*NOTREACHED*/
2751 Editor::snap_to_internal (MusicSample& start, RoundMode direction, bool for_mark, bool ensure_snap)
2753 const samplepos_t one_second = _session->sample_rate();
2754 const samplepos_t one_minute = _session->sample_rate() * 60;
2755 samplepos_t presnap = start.sample;
2759 switch (_snap_type) {
2760 case SnapToTimecodeFrame:
2761 case SnapToTimecodeSeconds:
2762 case SnapToTimecodeMinutes:
2763 return timecode_snap_to_internal (start, direction, for_mark);
2766 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2767 start.sample % (one_second/75) == 0) {
2768 /* start is already on a whole CD sample, do nothing */
2769 } else if (((direction == 0) && (start.sample % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2770 start.sample = (samplepos_t) ceil ((double) start.sample / (one_second / 75)) * (one_second / 75);
2772 start.sample = (samplepos_t) floor ((double) start.sample / (one_second / 75)) * (one_second / 75);
2775 start.set (start.sample, 0);
2780 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2781 start.sample % one_second == 0) {
2782 /* start is already on a whole second, do nothing */
2783 } else if (((direction == 0) && (start.sample % one_second > one_second / 2)) || (direction > 0)) {
2784 start.sample = (samplepos_t) ceil ((double) start.sample / one_second) * one_second;
2786 start.sample = (samplepos_t) floor ((double) start.sample / one_second) * one_second;
2789 start.set (start.sample, 0);
2794 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2795 start.sample % one_minute == 0) {
2796 /* start is already on a whole minute, do nothing */
2797 } else if (((direction == 0) && (start.sample % one_minute > one_minute / 2)) || (direction > 0)) {
2798 start.sample = (samplepos_t) ceil ((double) start.sample / one_minute) * one_minute;
2800 start.sample = (samplepos_t) floor ((double) start.sample / one_minute) * one_minute;
2803 start.set (start.sample, 0);
2808 start = _session->tempo_map().round_to_bar (start.sample, direction);
2812 start = _session->tempo_map().round_to_beat (start.sample, direction);
2815 case SnapToBeatDiv128:
2816 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 128, direction);
2818 case SnapToBeatDiv64:
2819 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 64, direction);
2821 case SnapToBeatDiv32:
2822 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 32, direction);
2824 case SnapToBeatDiv28:
2825 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 28, direction);
2827 case SnapToBeatDiv24:
2828 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 24, direction);
2830 case SnapToBeatDiv20:
2831 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 20, direction);
2833 case SnapToBeatDiv16:
2834 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 16, direction);
2836 case SnapToBeatDiv14:
2837 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 14, direction);
2839 case SnapToBeatDiv12:
2840 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 12, direction);
2842 case SnapToBeatDiv10:
2843 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 10, direction);
2845 case SnapToBeatDiv8:
2846 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 8, direction);
2848 case SnapToBeatDiv7:
2849 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 7, direction);
2851 case SnapToBeatDiv6:
2852 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 6, direction);
2854 case SnapToBeatDiv5:
2855 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 5, direction);
2857 case SnapToBeatDiv4:
2858 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 4, direction);
2860 case SnapToBeatDiv3:
2861 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 3, direction);
2863 case SnapToBeatDiv2:
2864 start = _session->tempo_map().round_to_quarter_note_subdivision (start.sample, 2, direction);
2872 _session->locations()->marks_either_side (start.sample, before, after);
2874 if (before == max_samplepos && after == max_samplepos) {
2875 /* No marks to snap to, so just don't snap */
2877 } else if (before == max_samplepos) {
2878 start.sample = after;
2879 } else if (after == max_samplepos) {
2880 start.sample = before;
2881 } else if (before != max_samplepos && after != max_samplepos) {
2882 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2883 start.sample = after;
2884 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2885 start.sample = before;
2886 else if (direction == 0 ) {
2887 if ((start.sample - before) < (after - start.sample)) {
2888 start.sample = before;
2890 start.sample = after;
2895 start.set (start.sample, 0);
2899 case SnapToRegionStart:
2900 case SnapToRegionEnd:
2901 case SnapToRegionSync:
2902 case SnapToRegionBoundary:
2903 if (!region_boundary_cache.empty()) {
2905 vector<samplepos_t>::iterator prev = region_boundary_cache.end ();
2906 vector<samplepos_t>::iterator next = region_boundary_cache.end ();
2908 if (direction > 0) {
2909 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.sample);
2911 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.sample);
2914 if (next != region_boundary_cache.begin ()) {
2919 samplepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2920 samplepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2922 if (start.sample > (p + n) / 2) {
2929 start.set (start.sample, 0);
2934 switch (_snap_mode) {
2944 if (presnap > start.sample) {
2945 if (presnap > (start.sample + pixel_to_sample(snap_threshold))) {
2946 start.set (presnap, 0);
2949 } else if (presnap < start.sample) {
2950 if (presnap < (start.sample - pixel_to_sample(snap_threshold))) {
2951 start.set (presnap, 0);
2956 /* handled at entry */
2963 Editor::setup_toolbar ()
2965 HBox* mode_box = manage(new HBox);
2966 mode_box->set_border_width (2);
2967 mode_box->set_spacing(2);
2969 HBox* mouse_mode_box = manage (new HBox);
2970 HBox* mouse_mode_hbox = manage (new HBox);
2971 VBox* mouse_mode_vbox = manage (new VBox);
2972 Alignment* mouse_mode_align = manage (new Alignment);
2974 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2975 mouse_mode_size_group->add_widget (smart_mode_button);
2976 mouse_mode_size_group->add_widget (mouse_move_button);
2977 mouse_mode_size_group->add_widget (mouse_cut_button);
2978 mouse_mode_size_group->add_widget (mouse_select_button);
2979 mouse_mode_size_group->add_widget (mouse_timefx_button);
2980 mouse_mode_size_group->add_widget (mouse_audition_button);
2981 mouse_mode_size_group->add_widget (mouse_draw_button);
2982 mouse_mode_size_group->add_widget (mouse_content_button);
2984 if (!Profile->get_mixbus()) {
2985 mouse_mode_size_group->add_widget (zoom_in_button);
2986 mouse_mode_size_group->add_widget (zoom_out_button);
2987 mouse_mode_size_group->add_widget (zoom_out_full_button);
2988 mouse_mode_size_group->add_widget (zoom_focus_selector);
2989 mouse_mode_size_group->add_widget (tav_shrink_button);
2990 mouse_mode_size_group->add_widget (tav_expand_button);
2992 mouse_mode_size_group->add_widget (zoom_preset_selector);
2993 mouse_mode_size_group->add_widget (visible_tracks_selector);
2996 mouse_mode_size_group->add_widget (snap_type_selector);
2997 mouse_mode_size_group->add_widget (snap_mode_selector);
2999 mouse_mode_size_group->add_widget (edit_point_selector);
3000 mouse_mode_size_group->add_widget (edit_mode_selector);
3002 mouse_mode_size_group->add_widget (*nudge_clock);
3003 mouse_mode_size_group->add_widget (nudge_forward_button);
3004 mouse_mode_size_group->add_widget (nudge_backward_button);
3006 mouse_mode_hbox->set_spacing (2);
3008 if (!ARDOUR::Profile->get_trx()) {
3009 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3012 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3013 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3015 if (!ARDOUR::Profile->get_mixbus()) {
3016 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3019 if (!ARDOUR::Profile->get_trx()) {
3020 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3021 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3022 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3023 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3026 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3028 mouse_mode_align->add (*mouse_mode_vbox);
3029 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3031 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3033 edit_mode_selector.set_name ("mouse mode button");
3035 if (!ARDOUR::Profile->get_trx()) {
3036 mode_box->pack_start (edit_mode_selector, false, false);
3039 mode_box->pack_start (*mouse_mode_box, false, false);
3043 _zoom_box.set_spacing (2);
3044 _zoom_box.set_border_width (2);
3048 zoom_preset_selector.set_name ("zoom button");
3049 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
3051 zoom_in_button.set_name ("zoom button");
3052 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3053 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3054 zoom_in_button.set_related_action (act);
3056 zoom_out_button.set_name ("zoom button");
3057 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3058 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3059 zoom_out_button.set_related_action (act);
3061 zoom_out_full_button.set_name ("zoom button");
3062 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3063 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3064 zoom_out_full_button.set_related_action (act);
3066 zoom_focus_selector.set_name ("zoom button");
3068 if (ARDOUR::Profile->get_mixbus()) {
3069 _zoom_box.pack_start (zoom_preset_selector, false, false);
3070 } else if (ARDOUR::Profile->get_trx()) {
3071 mode_box->pack_start (zoom_out_button, false, false);
3072 mode_box->pack_start (zoom_in_button, false, false);
3074 _zoom_box.pack_start (zoom_out_button, false, false);
3075 _zoom_box.pack_start (zoom_in_button, false, false);
3076 _zoom_box.pack_start (zoom_out_full_button, false, false);
3077 _zoom_box.pack_start (zoom_focus_selector, false, false);
3080 /* Track zoom buttons */
3081 _track_box.set_spacing (2);
3082 _track_box.set_border_width (2);
3084 visible_tracks_selector.set_name ("zoom button");
3085 if (Profile->get_mixbus()) {
3086 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3088 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3091 tav_expand_button.set_name ("zoom button");
3092 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3093 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3094 tav_expand_button.set_related_action (act);
3096 tav_shrink_button.set_name ("zoom button");
3097 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3098 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3099 tav_shrink_button.set_related_action (act);
3101 if (ARDOUR::Profile->get_mixbus()) {
3102 _track_box.pack_start (visible_tracks_selector);
3103 } else if (ARDOUR::Profile->get_trx()) {
3104 _track_box.pack_start (tav_shrink_button);
3105 _track_box.pack_start (tav_expand_button);
3107 _track_box.pack_start (visible_tracks_selector);
3108 _track_box.pack_start (tav_shrink_button);
3109 _track_box.pack_start (tav_expand_button);
3112 snap_box.set_spacing (2);
3113 snap_box.set_border_width (2);
3115 snap_type_selector.set_name ("mouse mode button");
3117 snap_mode_selector.set_name ("mouse mode button");
3119 edit_point_selector.set_name ("mouse mode button");
3121 snap_box.pack_start (snap_mode_selector, false, false);
3122 snap_box.pack_start (snap_type_selector, false, false);
3125 HBox *ep_box = manage (new HBox);
3126 ep_box->set_spacing (2);
3127 ep_box->set_border_width (2);
3129 ep_box->pack_start (edit_point_selector, false, false);
3133 HBox *nudge_box = manage (new HBox);
3134 nudge_box->set_spacing (2);
3135 nudge_box->set_border_width (2);
3137 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3138 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3140 nudge_box->pack_start (nudge_backward_button, false, false);
3141 nudge_box->pack_start (nudge_forward_button, false, false);
3142 nudge_box->pack_start (*nudge_clock, false, false);
3145 /* Pack everything in... */
3147 toolbar_hbox.set_spacing (2);
3148 toolbar_hbox.set_border_width (2);
3150 toolbar_hbox.pack_start (*mode_box, false, false);
3152 if (!ARDOUR::Profile->get_trx()) {
3154 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3156 toolbar_hbox.pack_start (_zoom_box, false, false);
3158 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3160 toolbar_hbox.pack_start (_track_box, false, false);
3162 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3164 toolbar_hbox.pack_start (snap_box, false, false);
3166 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3168 toolbar_hbox.pack_start (*ep_box, false, false);
3170 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3172 toolbar_hbox.pack_start (*nudge_box, false, false);
3175 toolbar_hbox.show_all ();
3179 Editor::build_edit_point_menu ()
3181 using namespace Menu_Helpers;
3183 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3184 if(!Profile->get_mixbus())
3185 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3186 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3188 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3192 Editor::build_edit_mode_menu ()
3194 using namespace Menu_Helpers;
3196 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3197 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3198 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3199 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3201 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3205 Editor::build_snap_mode_menu ()
3207 using namespace Menu_Helpers;
3209 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3210 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3211 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3213 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3217 Editor::build_snap_type_menu ()
3219 using namespace Menu_Helpers;
3221 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3222 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3223 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3224 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3225 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3226 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3227 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3228 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3229 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3230 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3231 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3232 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3233 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3234 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3235 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3236 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3237 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3238 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3239 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3240 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3241 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3242 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3243 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3244 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3245 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3246 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3247 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3248 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3249 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3250 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3252 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3257 Editor::setup_tooltips ()
3259 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3260 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3261 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3262 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3263 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3264 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3265 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3266 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3267 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3268 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3269 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3270 set_tooltip (zoom_in_button, _("Zoom In"));
3271 set_tooltip (zoom_out_button, _("Zoom Out"));
3272 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3273 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3274 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3275 set_tooltip (tav_expand_button, _("Expand Tracks"));
3276 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3277 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3278 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3279 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3280 set_tooltip (edit_point_selector, _("Edit Point"));
3281 set_tooltip (edit_mode_selector, _("Edit Mode"));
3282 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3286 Editor::convert_drop_to_paths (
3287 vector<string>& paths,
3288 const RefPtr<Gdk::DragContext>& /*context*/,
3291 const SelectionData& data,
3295 if (_session == 0) {
3299 vector<string> uris = data.get_uris();
3303 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3304 are actually URI lists. So do it by hand.
3307 if (data.get_target() != "text/plain") {
3311 /* Parse the "uri-list" format that Nautilus provides,
3312 where each pathname is delimited by \r\n.
3314 THERE MAY BE NO NULL TERMINATING CHAR!!!
3317 string txt = data.get_text();
3321 p = (char *) malloc (txt.length() + 1);
3322 txt.copy (p, txt.length(), 0);
3323 p[txt.length()] = '\0';
3329 while (g_ascii_isspace (*p))
3333 while (*q && (*q != '\n') && (*q != '\r')) {
3340 while (q > p && g_ascii_isspace (*q))
3345 uris.push_back (string (p, q - p + 1));
3349 p = strchr (p, '\n');
3361 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3362 if ((*i).substr (0,7) == "file://") {
3363 paths.push_back (Glib::filename_from_uri (*i));
3371 Editor::new_tempo_section ()
3376 Editor::map_transport_state ()
3378 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3380 if (_session && _session->transport_stopped()) {
3381 have_pending_keyboard_selection = false;
3384 update_loop_range_view ();
3388 Editor::transport_looped ()
3390 /* reset Playhead position interpolation.
3391 * see Editor::super_rapid_screen_update
3393 _last_update_time = 0;
3399 Editor::begin_selection_op_history ()
3401 selection_op_cmd_depth = 0;
3402 selection_op_history_it = 0;
3404 while(!selection_op_history.empty()) {
3405 delete selection_op_history.front();
3406 selection_op_history.pop_front();
3409 selection_undo_action->set_sensitive (false);
3410 selection_redo_action->set_sensitive (false);
3411 selection_op_history.push_front (&_selection_memento->get_state ());
3415 Editor::begin_reversible_selection_op (string name)
3418 //cerr << name << endl;
3419 /* begin/commit pairs can be nested */
3420 selection_op_cmd_depth++;
3425 Editor::commit_reversible_selection_op ()
3428 if (selection_op_cmd_depth == 1) {
3430 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3432 The user has undone some selection ops and then made a new one,
3433 making anything earlier in the list invalid.
3436 list<XMLNode *>::iterator it = selection_op_history.begin();
3437 list<XMLNode *>::iterator e_it = it;
3438 advance (e_it, selection_op_history_it);
3440 for ( ; it != e_it; ++it) {
3443 selection_op_history.erase (selection_op_history.begin(), e_it);
3446 selection_op_history.push_front (&_selection_memento->get_state ());
3447 selection_op_history_it = 0;
3449 selection_undo_action->set_sensitive (true);
3450 selection_redo_action->set_sensitive (false);
3453 if (selection_op_cmd_depth > 0) {
3454 selection_op_cmd_depth--;
3460 Editor::undo_selection_op ()
3463 selection_op_history_it++;
3465 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3466 if (n == selection_op_history_it) {
3467 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3468 selection_redo_action->set_sensitive (true);
3472 /* is there an earlier entry? */
3473 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3474 selection_undo_action->set_sensitive (false);
3480 Editor::redo_selection_op ()
3483 if (selection_op_history_it > 0) {
3484 selection_op_history_it--;
3487 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3488 if (n == selection_op_history_it) {
3489 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3490 selection_undo_action->set_sensitive (true);
3495 if (selection_op_history_it == 0) {
3496 selection_redo_action->set_sensitive (false);
3502 Editor::begin_reversible_command (string name)
3505 before.push_back (&_selection_memento->get_state ());
3506 _session->begin_reversible_command (name);
3511 Editor::begin_reversible_command (GQuark q)
3514 before.push_back (&_selection_memento->get_state ());
3515 _session->begin_reversible_command (q);
3520 Editor::abort_reversible_command ()
3523 while(!before.empty()) {
3524 delete before.front();
3527 _session->abort_reversible_command ();
3532 Editor::commit_reversible_command ()
3535 if (before.size() == 1) {
3536 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3537 redo_action->set_sensitive(false);
3538 undo_action->set_sensitive(true);
3539 begin_selection_op_history ();
3542 if (before.empty()) {
3543 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3548 _session->commit_reversible_command ();
3553 Editor::history_changed ()
3557 if (undo_action && _session) {
3558 if (_session->undo_depth() == 0) {
3559 label = S_("Command|Undo");
3561 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3563 undo_action->property_label() = label;
3566 if (redo_action && _session) {
3567 if (_session->redo_depth() == 0) {
3569 redo_action->set_sensitive (false);
3571 label = string_compose(_("Redo (%1)"), _session->next_redo());
3572 redo_action->set_sensitive (true);
3574 redo_action->property_label() = label;
3579 Editor::duplicate_range (bool with_dialog)
3583 RegionSelection rs = get_regions_from_selection_and_entered ();
3585 if ( selection->time.length() == 0 && rs.empty()) {
3591 ArdourDialog win (_("Duplicate"));
3592 Label label (_("Number of duplications:"));
3593 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3594 SpinButton spinner (adjustment, 0.0, 1);
3597 win.get_vbox()->set_spacing (12);
3598 win.get_vbox()->pack_start (hbox);
3599 hbox.set_border_width (6);
3600 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3602 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3603 place, visually. so do this by hand.
3606 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3607 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3608 spinner.grab_focus();
3614 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3615 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3616 win.set_default_response (RESPONSE_ACCEPT);
3618 spinner.grab_focus ();
3620 switch (win.run ()) {
3621 case RESPONSE_ACCEPT:
3627 times = adjustment.get_value();
3630 if ((current_mouse_mode() == Editing::MouseRange)) {
3631 if (selection->time.length()) {
3632 duplicate_selection (times);
3634 } else if (get_smart_mode()) {
3635 if (selection->time.length()) {
3636 duplicate_selection (times);
3638 duplicate_some_regions (rs, times);
3640 duplicate_some_regions (rs, times);
3645 Editor::set_edit_mode (EditMode m)
3647 Config->set_edit_mode (m);
3651 Editor::cycle_edit_mode ()
3653 switch (Config->get_edit_mode()) {
3655 Config->set_edit_mode (Ripple);
3659 Config->set_edit_mode (Lock);
3662 Config->set_edit_mode (Slide);
3668 Editor::edit_mode_selection_done ( EditMode m )
3670 Config->set_edit_mode ( m );
3674 Editor::snap_type_selection_done (SnapType snaptype)
3676 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3678 ract->set_active ();
3683 Editor::snap_mode_selection_done (SnapMode mode)
3685 RefPtr<RadioAction> ract = snap_mode_action (mode);
3688 ract->set_active (true);
3693 Editor::cycle_edit_point (bool with_marker)
3695 if(Profile->get_mixbus())
3696 with_marker = false;
3698 switch (_edit_point) {
3700 set_edit_point_preference (EditAtPlayhead);
3702 case EditAtPlayhead:
3704 set_edit_point_preference (EditAtSelectedMarker);
3706 set_edit_point_preference (EditAtMouse);
3709 case EditAtSelectedMarker:
3710 set_edit_point_preference (EditAtMouse);
3716 Editor::edit_point_selection_done (EditPoint ep)
3718 set_edit_point_preference ( ep );
3722 Editor::build_zoom_focus_menu ()
3724 using namespace Menu_Helpers;
3726 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3727 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3728 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3729 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3730 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3731 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3733 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3737 Editor::zoom_focus_selection_done ( ZoomFocus f )
3739 RefPtr<RadioAction> ract = zoom_focus_action (f);
3741 ract->set_active ();
3746 Editor::build_track_count_menu ()
3748 using namespace Menu_Helpers;
3750 if (!Profile->get_mixbus()) {
3751 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3752 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3753 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3754 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3755 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3756 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3757 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3758 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3759 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3760 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3761 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3762 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3763 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3765 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3766 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3767 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3768 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3769 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3770 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3771 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3772 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3773 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3774 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3776 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3777 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3778 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3779 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3780 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3781 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3782 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3783 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3784 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3785 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3786 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Extents"), sigc::mem_fun(*this, &Editor::temporal_zoom_extents)));
3787 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3792 Editor::set_zoom_preset (int64_t ms)
3795 temporal_zoom_session();
3799 ARDOUR::samplecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3800 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3804 Editor::set_visible_track_count (int32_t n)
3806 _visible_track_count = n;
3808 /* if the canvas hasn't really been allocated any size yet, just
3809 record the desired number of visible tracks and return. when canvas
3810 allocation happens, we will get called again and then we can do the
3814 if (_visible_canvas_height <= 1) {
3820 DisplaySuspender ds;
3822 if (_visible_track_count > 0) {
3823 h = trackviews_height() / _visible_track_count;
3824 std::ostringstream s;
3825 s << _visible_track_count;
3827 } else if (_visible_track_count == 0) {
3829 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
3830 if ((*i)->marked_for_display()) {
3832 TimeAxisView::Children cl ((*i)->get_child_list ());
3833 for (TimeAxisView::Children::const_iterator j = cl.begin(); j != cl.end(); ++j) {
3834 if ((*j)->marked_for_display()) {
3841 visible_tracks_selector.set_text (X_("*"));
3844 h = trackviews_height() / n;
3847 /* negative value means that the visible track count has
3848 been overridden by explicit track height changes.
3850 visible_tracks_selector.set_text (X_("*"));
3854 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3855 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3858 if (str != visible_tracks_selector.get_text()) {
3859 visible_tracks_selector.set_text (str);
3864 Editor::override_visible_track_count ()
3866 _visible_track_count = -1;
3867 visible_tracks_selector.set_text ( _("*") );
3871 Editor::edit_controls_button_release (GdkEventButton* ev)
3873 if (Keyboard::is_context_menu_event (ev)) {
3874 ARDOUR_UI::instance()->add_route ();
3875 } else if (ev->button == 1) {
3876 selection->clear_tracks ();
3883 Editor::mouse_select_button_release (GdkEventButton* ev)
3885 /* this handles just right-clicks */
3887 if (ev->button != 3) {
3895 Editor::set_zoom_focus (ZoomFocus f)
3897 string str = zoom_focus_strings[(int)f];
3899 if (str != zoom_focus_selector.get_text()) {
3900 zoom_focus_selector.set_text (str);
3903 if (zoom_focus != f) {
3910 Editor::cycle_zoom_focus ()
3912 switch (zoom_focus) {
3914 set_zoom_focus (ZoomFocusRight);
3916 case ZoomFocusRight:
3917 set_zoom_focus (ZoomFocusCenter);
3919 case ZoomFocusCenter:
3920 set_zoom_focus (ZoomFocusPlayhead);
3922 case ZoomFocusPlayhead:
3923 set_zoom_focus (ZoomFocusMouse);
3925 case ZoomFocusMouse:
3926 set_zoom_focus (ZoomFocusEdit);
3929 set_zoom_focus (ZoomFocusLeft);
3935 Editor::set_show_measures (bool yn)
3937 if (_show_measures != yn) {
3940 if ((_show_measures = yn) == true) {
3942 tempo_lines->show();
3945 std::vector<TempoMap::BBTPoint> grid;
3946 compute_current_bbt_points (grid, _leftmost_sample, _leftmost_sample + current_page_samples());
3947 draw_measures (grid);
3955 Editor::toggle_follow_playhead ()
3957 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3959 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3960 set_follow_playhead (tact->get_active());
3964 /** @param yn true to follow playhead, otherwise false.
3965 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3968 Editor::set_follow_playhead (bool yn, bool catch_up)
3970 if (_follow_playhead != yn) {
3971 if ((_follow_playhead = yn) == true && catch_up) {
3973 reset_x_origin_to_follow_playhead ();
3980 Editor::toggle_stationary_playhead ()
3982 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3984 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3985 set_stationary_playhead (tact->get_active());
3990 Editor::set_stationary_playhead (bool yn)
3992 if (_stationary_playhead != yn) {
3993 if ((_stationary_playhead = yn) == true) {
3995 // FIXME need a 3.0 equivalent of this 2.X call
3996 // update_current_screen ();
4003 Editor::playlist_selector () const
4005 return *_playlist_selector;
4009 Editor::get_paste_offset (samplepos_t pos, unsigned paste_count, samplecnt_t duration)
4011 if (paste_count == 0) {
4012 /* don't bother calculating an offset that will be zero anyway */
4016 /* calculate basic unsnapped multi-paste offset */
4017 samplecnt_t offset = paste_count * duration;
4019 /* snap offset so pos + offset is aligned to the grid */
4020 MusicSample offset_pos (pos + offset, 0);
4021 snap_to(offset_pos, RoundUpMaybe);
4022 offset = offset_pos.sample - pos;
4028 Editor::get_grid_beat_divisions(samplepos_t position)
4030 switch (_snap_type) {
4031 case SnapToBeatDiv128: return 128;
4032 case SnapToBeatDiv64: return 64;
4033 case SnapToBeatDiv32: return 32;
4034 case SnapToBeatDiv28: return 28;
4035 case SnapToBeatDiv24: return 24;
4036 case SnapToBeatDiv20: return 20;
4037 case SnapToBeatDiv16: return 16;
4038 case SnapToBeatDiv14: return 14;
4039 case SnapToBeatDiv12: return 12;
4040 case SnapToBeatDiv10: return 10;
4041 case SnapToBeatDiv8: return 8;
4042 case SnapToBeatDiv7: return 7;
4043 case SnapToBeatDiv6: return 6;
4044 case SnapToBeatDiv5: return 5;
4045 case SnapToBeatDiv4: return 4;
4046 case SnapToBeatDiv3: return 3;
4047 case SnapToBeatDiv2: return 2;
4053 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4054 if the grid is non-musical, returns 0.
4055 if the grid is snapped to bars, returns -1.
4056 @param event_state the current keyboard modifier mask.
4059 Editor::get_grid_music_divisions (uint32_t event_state)
4061 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4065 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4069 switch (_snap_type) {
4070 case SnapToBeatDiv128: return 128;
4071 case SnapToBeatDiv64: return 64;
4072 case SnapToBeatDiv32: return 32;
4073 case SnapToBeatDiv28: return 28;
4074 case SnapToBeatDiv24: return 24;
4075 case SnapToBeatDiv20: return 20;
4076 case SnapToBeatDiv16: return 16;
4077 case SnapToBeatDiv14: return 14;
4078 case SnapToBeatDiv12: return 12;
4079 case SnapToBeatDiv10: return 10;
4080 case SnapToBeatDiv8: return 8;
4081 case SnapToBeatDiv7: return 7;
4082 case SnapToBeatDiv6: return 6;
4083 case SnapToBeatDiv5: return 5;
4084 case SnapToBeatDiv4: return 4;
4085 case SnapToBeatDiv3: return 3;
4086 case SnapToBeatDiv2: return 2;
4087 case SnapToBeat: return 1;
4088 case SnapToBar : return -1;
4095 Editor::get_grid_type_as_beats (bool& success, samplepos_t position)
4099 const unsigned divisions = get_grid_beat_divisions(position);
4101 return Temporal::Beats(1.0 / (double)get_grid_beat_divisions(position));
4104 switch (_snap_type) {
4106 return Temporal::Beats(4.0 / _session->tempo_map().meter_at_sample (position).note_divisor());
4109 const Meter& m = _session->tempo_map().meter_at_sample (position);
4110 return Temporal::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4118 return Temporal::Beats();
4122 Editor::get_nudge_distance (samplepos_t pos, samplecnt_t& next)
4126 ret = nudge_clock->current_duration (pos);
4127 next = ret + 1; /* XXXX fix me */
4133 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4135 ArdourDialog dialog (_("Playlist Deletion"));
4136 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4137 "If it is kept, its audio files will not be cleaned.\n"
4138 "If it is deleted, audio files used by it alone will be cleaned."),
4141 dialog.set_position (WIN_POS_CENTER);
4142 dialog.get_vbox()->pack_start (label);
4146 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4147 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4148 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4149 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4150 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4152 // by default gtk uses the left most button
4153 keep->grab_focus ();
4155 switch (dialog.run ()) {
4157 /* keep this and all remaining ones */
4162 /* delete this and all others */
4166 case RESPONSE_ACCEPT:
4167 /* delete the playlist */
4171 case RESPONSE_REJECT:
4172 /* keep the playlist */
4184 Editor::audio_region_selection_covers (samplepos_t where)
4186 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4187 if ((*a)->region()->covers (where)) {
4196 Editor::prepare_for_cleanup ()
4198 cut_buffer->clear_regions ();
4199 cut_buffer->clear_playlists ();
4201 selection->clear_regions ();
4202 selection->clear_playlists ();
4204 _regions->suspend_redisplay ();
4208 Editor::finish_cleanup ()
4210 _regions->resume_redisplay ();
4214 Editor::transport_loop_location()
4217 return _session->locations()->auto_loop_location();
4224 Editor::transport_punch_location()
4227 return _session->locations()->auto_punch_location();
4234 Editor::control_layout_scroll (GdkEventScroll* ev)
4236 /* Just forward to the normal canvas scroll method. The coordinate
4237 systems are different but since the canvas is always larger than the
4238 track headers, and aligned with the trackview area, this will work.
4240 In the not too distant future this layout is going away anyway and
4241 headers will be on the canvas.
4243 return canvas_scroll_event (ev, false);
4247 Editor::session_state_saved (string)
4250 _snapshots->redisplay ();
4254 Editor::maximise_editing_space ()
4260 Gtk::Window* toplevel = current_toplevel();
4263 toplevel->fullscreen ();
4269 Editor::restore_editing_space ()
4275 Gtk::Window* toplevel = current_toplevel();
4278 toplevel->unfullscreen();
4284 * Make new playlists for a given track and also any others that belong
4285 * to the same active route group with the `select' property.
4290 Editor::new_playlists (TimeAxisView* v)
4292 begin_reversible_command (_("new playlists"));
4293 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4294 _session->playlists->get (playlists);
4295 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4296 commit_reversible_command ();
4300 * Use a copy of the current playlist for a given track and also any others that belong
4301 * to the same active route group with the `select' property.
4306 Editor::copy_playlists (TimeAxisView* v)
4308 begin_reversible_command (_("copy playlists"));
4309 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4310 _session->playlists->get (playlists);
4311 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4312 commit_reversible_command ();
4315 /** Clear the current playlist for a given track and also any others that belong
4316 * to the same active route group with the `select' property.
4321 Editor::clear_playlists (TimeAxisView* v)
4323 begin_reversible_command (_("clear playlists"));
4324 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4325 _session->playlists->get (playlists);
4326 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4327 commit_reversible_command ();
4331 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4333 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4337 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4339 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4343 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4345 atv.clear_playlist ();
4349 Editor::get_y_origin () const
4351 return vertical_adjustment.get_value ();
4354 /** Queue up a change to the viewport x origin.
4355 * @param sample New x origin.
4358 Editor::reset_x_origin (samplepos_t sample)
4360 pending_visual_change.add (VisualChange::TimeOrigin);
4361 pending_visual_change.time_origin = sample;
4362 ensure_visual_change_idle_handler ();
4366 Editor::reset_y_origin (double y)
4368 pending_visual_change.add (VisualChange::YOrigin);
4369 pending_visual_change.y_origin = y;
4370 ensure_visual_change_idle_handler ();
4374 Editor::reset_zoom (samplecnt_t spp)
4376 if (spp == samples_per_pixel) {
4380 pending_visual_change.add (VisualChange::ZoomLevel);
4381 pending_visual_change.samples_per_pixel = spp;
4382 ensure_visual_change_idle_handler ();
4386 Editor::reposition_and_zoom (samplepos_t sample, double fpu)
4388 reset_x_origin (sample);
4391 if (!no_save_visual) {
4392 undo_visual_stack.push_back (current_visual_state(false));
4396 Editor::VisualState::VisualState (bool with_tracks)
4397 : gui_state (with_tracks ? new GUIObjectState : 0)
4401 Editor::VisualState::~VisualState ()
4406 Editor::VisualState*
4407 Editor::current_visual_state (bool with_tracks)
4409 VisualState* vs = new VisualState (with_tracks);
4410 vs->y_position = vertical_adjustment.get_value();
4411 vs->samples_per_pixel = samples_per_pixel;
4412 vs->_leftmost_sample = _leftmost_sample;
4413 vs->zoom_focus = zoom_focus;
4416 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4423 Editor::undo_visual_state ()
4425 if (undo_visual_stack.empty()) {
4429 VisualState* vs = undo_visual_stack.back();
4430 undo_visual_stack.pop_back();
4433 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4436 use_visual_state (*vs);
4441 Editor::redo_visual_state ()
4443 if (redo_visual_stack.empty()) {
4447 VisualState* vs = redo_visual_stack.back();
4448 redo_visual_stack.pop_back();
4450 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4451 // why do we check here?
4452 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4455 use_visual_state (*vs);
4460 Editor::swap_visual_state ()
4462 if (undo_visual_stack.empty()) {
4463 redo_visual_state ();
4465 undo_visual_state ();
4470 Editor::use_visual_state (VisualState& vs)
4472 PBD::Unwinder<bool> nsv (no_save_visual, true);
4473 DisplaySuspender ds;
4475 vertical_adjustment.set_value (vs.y_position);
4477 set_zoom_focus (vs.zoom_focus);
4478 reposition_and_zoom (vs._leftmost_sample, vs.samples_per_pixel);
4481 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4483 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4484 (*i)->clear_property_cache();
4485 (*i)->reset_visual_state ();
4489 _routes->update_visibility ();
4492 /** This is the core function that controls the zoom level of the canvas. It is called
4493 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4494 * @param spp new number of samples per pixel
4497 Editor::set_samples_per_pixel (samplecnt_t spp)
4503 const samplecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->sample_rate() : 48000);
4504 const samplecnt_t lots_of_pixels = 4000;
4506 /* if the zoom level is greater than what you'd get trying to display 3
4507 * days of audio on a really big screen, then it's too big.
4510 if (spp * lots_of_pixels > three_days) {
4514 samples_per_pixel = spp;
4518 Editor::on_samples_per_pixel_changed ()
4521 tempo_lines->tempo_map_changed(_session->tempo_map().music_origin());
4524 bool const showing_time_selection = selection->time.length() > 0;
4526 if (showing_time_selection && selection->time.start () != selection->time.end_sample ()) {
4527 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4528 (*i)->reshow_selection (selection->time);
4532 ZoomChanged (); /* EMIT_SIGNAL */
4534 ArdourCanvas::GtkCanvasViewport* c;
4536 c = get_track_canvas();
4538 c->canvas()->zoomed ();
4541 if (playhead_cursor) {
4542 playhead_cursor->set_position (playhead_cursor->current_sample ());
4545 refresh_location_display();
4546 _summary->set_overlays_dirty ();
4548 update_marker_labels ();
4554 Editor::playhead_cursor_sample () const
4556 return playhead_cursor->current_sample();
4560 Editor::queue_visual_videotimeline_update ()
4562 pending_visual_change.add (VisualChange::VideoTimeline);
4563 ensure_visual_change_idle_handler ();
4567 Editor::ensure_visual_change_idle_handler ()
4569 if (pending_visual_change.idle_handler_id < 0) {
4570 // see comment in add_to_idle_resize above.
4571 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4572 pending_visual_change.being_handled = false;
4577 Editor::_idle_visual_changer (void* arg)
4579 return static_cast<Editor*>(arg)->idle_visual_changer ();
4583 Editor::pre_render ()
4585 visual_change_queued = false;
4587 if (pending_visual_change.pending != 0) {
4588 ensure_visual_change_idle_handler();
4593 Editor::idle_visual_changer ()
4595 pending_visual_change.idle_handler_id = -1;
4597 if (pending_visual_change.pending == 0) {
4601 /* set_horizontal_position() below (and maybe other calls) call
4602 gtk_main_iteration(), so it's possible that a signal will be handled
4603 half-way through this method. If this signal wants an
4604 idle_visual_changer we must schedule another one after this one, so
4605 mark the idle_handler_id as -1 here to allow that. Also make a note
4606 that we are doing the visual change, so that changes in response to
4607 super-rapid-screen-update can be dropped if we are still processing
4611 if (visual_change_queued) {
4615 pending_visual_change.being_handled = true;
4617 VisualChange vc = pending_visual_change;
4619 pending_visual_change.pending = (VisualChange::Type) 0;
4621 visual_changer (vc);
4623 pending_visual_change.being_handled = false;
4625 visual_change_queued = true;
4627 return 0; /* this is always a one-shot call */
4631 Editor::visual_changer (const VisualChange& vc)
4634 * Changed first so the correct horizontal canvas position is calculated in
4635 * Editor::set_horizontal_position
4637 if (vc.pending & VisualChange::ZoomLevel) {
4638 set_samples_per_pixel (vc.samples_per_pixel);
4641 if (vc.pending & VisualChange::TimeOrigin) {
4642 double new_time_origin = sample_to_pixel_unrounded (vc.time_origin);
4643 set_horizontal_position (new_time_origin);
4646 if (vc.pending & VisualChange::YOrigin) {
4647 vertical_adjustment.set_value (vc.y_origin);
4651 * Now the canvas is in the final state before render the canvas items that
4652 * support the Item::prepare_for_render interface can calculate the correct
4653 * item to visible canvas intersection.
4655 if (vc.pending & VisualChange::ZoomLevel) {
4656 on_samples_per_pixel_changed ();
4658 compute_fixed_ruler_scale ();
4660 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4661 update_tempo_based_rulers ();
4664 if (!(vc.pending & VisualChange::ZoomLevel)) {
4666 * If the canvas is not being zoomed then the canvas items will not change
4667 * and cause Item::prepare_for_render to be called so do it here manually.
4669 * Not ideal, but I can't think of a better solution atm.
4671 _track_canvas->prepare_for_render();
4674 // If we are only scrolling vertically there is no need to update these
4675 if (vc.pending != VisualChange::YOrigin) {
4676 update_fixed_rulers ();
4677 redisplay_tempo (true);
4679 /* video frames & position need to be updated for zoom, horiz-scroll
4680 * and (explicitly) VisualChange::VideoTimeline.
4682 update_video_timeline();
4685 _summary->set_overlays_dirty ();
4688 struct EditorOrderTimeAxisSorter {
4689 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4690 return a->order () < b->order ();
4695 Editor::sort_track_selection (TrackViewList& sel)
4697 EditorOrderTimeAxisSorter cmp;
4702 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4705 samplepos_t where = 0;
4706 EditPoint ep = _edit_point;
4708 if (Profile->get_mixbus()) {
4709 if (ep == EditAtSelectedMarker) {
4710 ep = EditAtPlayhead;
4714 if (from_outside_canvas && (ep == EditAtMouse)) {
4715 ep = EditAtPlayhead;
4716 } else if (from_context_menu && (ep == EditAtMouse)) {
4717 return canvas_event_sample (&context_click_event, 0, 0);
4720 if (entered_marker) {
4721 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4722 return entered_marker->position();
4725 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4726 ep = EditAtSelectedMarker;
4729 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4730 ep = EditAtPlayhead;
4733 MusicSample snap_mf (0, 0);
4736 case EditAtPlayhead:
4737 if (_dragging_playhead && _control_scroll_target) {
4738 where = *_control_scroll_target;
4740 where = _session->audible_sample();
4742 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4745 case EditAtSelectedMarker:
4746 if (!selection->markers.empty()) {
4748 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4751 where = loc->start();
4755 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4763 if (!mouse_sample (where, ignored)) {
4764 /* XXX not right but what can we do ? */
4767 snap_mf.sample = where;
4769 where = snap_mf.sample;
4770 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4778 Editor::set_loop_range (samplepos_t start, samplepos_t end, string cmd)
4780 if (!_session) return;
4782 begin_reversible_command (cmd);
4786 if ((tll = transport_loop_location()) == 0) {
4787 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4788 XMLNode &before = _session->locations()->get_state();
4789 _session->locations()->add (loc, true);
4790 _session->set_auto_loop_location (loc);
4791 XMLNode &after = _session->locations()->get_state();
4792 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4794 XMLNode &before = tll->get_state();
4795 tll->set_hidden (false, this);
4796 tll->set (start, end);
4797 XMLNode &after = tll->get_state();
4798 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4801 commit_reversible_command ();
4805 Editor::set_punch_range (samplepos_t start, samplepos_t end, string cmd)
4807 if (!_session) return;
4809 begin_reversible_command (cmd);
4813 if ((tpl = transport_punch_location()) == 0) {
4814 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4815 XMLNode &before = _session->locations()->get_state();
4816 _session->locations()->add (loc, true);
4817 _session->set_auto_punch_location (loc);
4818 XMLNode &after = _session->locations()->get_state();
4819 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4821 XMLNode &before = tpl->get_state();
4822 tpl->set_hidden (false, this);
4823 tpl->set (start, end);
4824 XMLNode &after = tpl->get_state();
4825 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4828 commit_reversible_command ();
4831 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4832 * @param rs List to which found regions are added.
4833 * @param where Time to look at.
4834 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4837 Editor::get_regions_at (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4839 const TrackViewList* tracks;
4842 tracks = &track_views;
4847 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4849 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4852 boost::shared_ptr<Track> tr;
4853 boost::shared_ptr<Playlist> pl;
4855 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4857 boost::shared_ptr<RegionList> regions = pl->regions_at (where);
4859 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4860 RegionView* rv = rtv->view()->find_view (*i);
4871 Editor::get_regions_after (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4873 const TrackViewList* tracks;
4876 tracks = &track_views;
4881 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4882 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4884 boost::shared_ptr<Track> tr;
4885 boost::shared_ptr<Playlist> pl;
4887 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4889 boost::shared_ptr<RegionList> regions = pl->regions_touched (where, max_samplepos);
4891 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4893 RegionView* rv = rtv->view()->find_view (*i);
4904 /** Get regions using the following method:
4906 * Make a region list using:
4907 * (a) any selected regions
4908 * (b) the intersection of any selected tracks and the edit point(*)
4909 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4911 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4913 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4917 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4919 RegionSelection regions;
4921 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4922 regions.add (entered_regionview);
4924 regions = selection->regions;
4927 if ( regions.empty() ) {
4928 TrackViewList tracks = selection->tracks;
4930 if (!tracks.empty()) {
4931 /* no region selected or entered, but some selected tracks:
4932 * act on all regions on the selected tracks at the edit point
4934 samplepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
4935 get_regions_at(regions, where, tracks);
4942 /** Get regions using the following method:
4944 * Make a region list using:
4945 * (a) any selected regions
4946 * (b) the intersection of any selected tracks and the edit point(*)
4947 * (c) if neither exists, then whatever region is under the mouse
4949 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4951 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4954 Editor::get_regions_from_selection_and_mouse (samplepos_t pos)
4956 RegionSelection regions;
4958 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4959 regions.add (entered_regionview);
4961 regions = selection->regions;
4964 if ( regions.empty() ) {
4965 TrackViewList tracks = selection->tracks;
4967 if (!tracks.empty()) {
4968 /* no region selected or entered, but some selected tracks:
4969 * act on all regions on the selected tracks at the edit point
4971 get_regions_at(regions, pos, tracks);
4978 /** Start with regions that are selected, or the entered regionview if none are selected.
4979 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4980 * of the regions that we started with.
4984 Editor::get_regions_from_selection_and_entered () const
4986 RegionSelection regions = selection->regions;
4988 if (regions.empty() && entered_regionview) {
4989 regions.add (entered_regionview);
4996 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4998 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4999 RouteTimeAxisView* rtav;
5001 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5002 boost::shared_ptr<Playlist> pl;
5003 std::vector<boost::shared_ptr<Region> > results;
5004 boost::shared_ptr<Track> tr;
5006 if ((tr = rtav->track()) == 0) {
5011 if ((pl = (tr->playlist())) != 0) {
5012 boost::shared_ptr<Region> r = pl->region_by_id (id);
5014 RegionView* rv = rtav->view()->find_view (r);
5016 regions.push_back (rv);
5025 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > > &selection) const
5028 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5029 MidiTimeAxisView* mtav;
5031 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5033 mtav->get_per_region_note_selection (selection);
5040 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5042 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5044 RouteTimeAxisView* tatv;
5046 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5048 boost::shared_ptr<Playlist> pl;
5049 vector<boost::shared_ptr<Region> > results;
5051 boost::shared_ptr<Track> tr;
5053 if ((tr = tatv->track()) == 0) {
5058 if ((pl = (tr->playlist())) != 0) {
5059 if (src_comparison) {
5060 pl->get_source_equivalent_regions (region, results);
5062 pl->get_region_list_equivalent_regions (region, results);
5066 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5067 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5068 regions.push_back (marv);
5077 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
5079 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5080 RouteTimeAxisView* tatv;
5081 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5082 if (!tatv->track()) {
5085 RegionView* marv = tatv->view()->find_view (region);
5095 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5097 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5098 RouteTimeAxisView* rtav;
5099 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5100 if (rtav->route() == route) {
5109 Editor::show_rhythm_ferret ()
5111 if (rhythm_ferret == 0) {
5112 rhythm_ferret = new RhythmFerret(*this);
5115 rhythm_ferret->set_session (_session);
5116 rhythm_ferret->show ();
5117 rhythm_ferret->present ();
5121 Editor::first_idle ()
5123 MessageDialog* dialog = 0;
5125 if (track_views.size() > 1) {
5126 Timers::TimerSuspender t;
5127 dialog = new MessageDialog (
5128 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5132 ARDOUR_UI::instance()->flush_pending (60);
5135 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5139 /* now that all regionviews should exist, setup region selection */
5143 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5144 /* this is cumulative: rs is NOT cleared each time */
5145 get_regionviews_by_id (*pr, rs);
5148 selection->set (rs);
5150 // first idle adds route children (automation tracks), so we need to redisplay here
5151 _routes->redisplay ();
5155 if (_session->undo_depth() == 0) {
5156 undo_action->set_sensitive(false);
5158 redo_action->set_sensitive(false);
5159 begin_selection_op_history ();
5165 Editor::_idle_resize (gpointer arg)
5167 return ((Editor*)arg)->idle_resize ();
5171 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5173 if (resize_idle_id < 0) {
5174 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5175 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5176 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5178 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5179 _pending_resize_amount = 0;
5182 /* make a note of the smallest resulting height, so that we can clamp the
5183 lower limit at TimeAxisView::hSmall */
5185 int32_t min_resulting = INT32_MAX;
5187 _pending_resize_amount += h;
5188 _pending_resize_view = view;
5190 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5192 if (selection->tracks.contains (_pending_resize_view)) {
5193 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5194 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5198 if (min_resulting < 0) {
5203 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5204 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5208 /** Handle pending resizing of tracks */
5210 Editor::idle_resize ()
5212 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5214 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5215 selection->tracks.contains (_pending_resize_view)) {
5217 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5218 if (*i != _pending_resize_view) {
5219 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5224 _pending_resize_amount = 0;
5225 _group_tabs->set_dirty ();
5226 resize_idle_id = -1;
5234 ENSURE_GUI_THREAD (*this, &Editor::located);
5237 playhead_cursor->set_position (_session->audible_sample ());
5238 if (_follow_playhead && !_pending_initial_locate) {
5239 reset_x_origin_to_follow_playhead ();
5243 _pending_locate_request = false;
5244 _pending_initial_locate = false;
5245 _last_update_time = 0;
5249 Editor::region_view_added (RegionView * rv)
5251 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5253 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5254 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5255 if (rv->region()->id () == (*rnote).first) {
5256 mrv->select_notes ((*rnote).second);
5257 selection->pending_midi_note_selection.erase(rnote);
5263 _summary->set_background_dirty ();
5267 Editor::region_view_removed ()
5269 _summary->set_background_dirty ();
5273 Editor::axis_view_by_stripable (boost::shared_ptr<Stripable> s) const
5275 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5276 if ((*j)->stripable() == s) {
5285 Editor::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
5287 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5288 if ((*j)->control() == c) {
5292 TimeAxisView::Children kids = (*j)->get_child_list ();
5294 for (TimeAxisView::Children::iterator k = kids.begin(); k != kids.end(); ++k) {
5295 if ((*k)->control() == c) {
5305 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5309 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5310 TimeAxisView* tv = time_axis_view_from_stripable (*i);
5320 Editor::suspend_route_redisplay ()
5323 _routes->suspend_redisplay();
5328 Editor::resume_route_redisplay ()
5331 _routes->redisplay(); // queue redisplay
5332 _routes->resume_redisplay();
5337 Editor::add_vcas (VCAList& vlist)
5341 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5342 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5345 add_stripables (sl);
5349 Editor::add_routes (RouteList& rlist)
5353 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5357 add_stripables (sl);
5361 Editor::add_stripables (StripableList& sl)
5363 list<TimeAxisView*> new_views;
5364 boost::shared_ptr<VCA> v;
5365 boost::shared_ptr<Route> r;
5366 TrackViewList new_selection;
5367 bool from_scratch = (track_views.size() == 0);
5369 sl.sort (Stripable::Sorter());
5371 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5373 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5375 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5377 new_views.push_back (vtv);
5379 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5381 if (r->is_auditioner() || r->is_monitor()) {
5385 RouteTimeAxisView* rtv;
5386 DataType dt = r->input()->default_type();
5388 if (dt == ARDOUR::DataType::AUDIO) {
5389 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5391 } else if (dt == ARDOUR::DataType::MIDI) {
5392 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5395 throw unknown_type();
5398 new_views.push_back (rtv);
5399 track_views.push_back (rtv);
5400 new_selection.push_back (rtv);
5402 rtv->effective_gain_display ();
5404 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5405 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5409 if (new_views.size() > 0) {
5410 _routes->time_axis_views_added (new_views);
5411 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5414 /* note: !new_selection.empty() means that we got some routes rather
5418 if (!from_scratch && !new_selection.empty()) {
5419 selection->set (new_selection);
5420 begin_selection_op_history();
5423 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5424 show_editor_mixer (true);
5427 editor_list_button.set_sensitive (true);
5431 Editor::timeaxisview_deleted (TimeAxisView *tv)
5433 if (tv == entered_track) {
5437 if (_session && _session->deletion_in_progress()) {
5438 /* the situation is under control */
5442 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5444 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5446 _routes->route_removed (tv);
5448 TimeAxisView::Children c = tv->get_child_list ();
5449 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5450 if (entered_track == i->get()) {
5455 /* remove it from the list of track views */
5457 TrackViewList::iterator i;
5459 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5460 i = track_views.erase (i);
5463 /* update whatever the current mixer strip is displaying, if revelant */
5465 boost::shared_ptr<Route> route;
5468 route = rtav->route ();
5471 if (current_mixer_strip && current_mixer_strip->route() == route) {
5473 TimeAxisView* next_tv;
5475 if (track_views.empty()) {
5477 } else if (i == track_views.end()) {
5478 next_tv = track_views.front();
5483 // skip VCAs (cannot be selected, n/a in editor-mixer)
5484 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5485 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5486 next_tv = track_views.front();
5488 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5489 /* just in case: no master, only a VCA remains */
5495 set_selected_mixer_strip (*next_tv);
5497 /* make the editor mixer strip go away setting the
5498 * button to inactive (which also unticks the menu option)
5501 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5507 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5513 DisplaySuspender ds;
5514 PresentationInfo::ChangeSuspender cs;
5516 if (apply_to_selection) {
5517 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5519 TrackSelection::iterator j = i;
5522 hide_track_in_display (*i, false);
5527 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5529 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5530 // this will hide the mixer strip
5531 set_selected_mixer_strip (*tv);
5534 _routes->hide_track_in_display (*tv);
5539 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5544 _routes->show_track_in_display (*tv);
5545 if (move_into_view) {
5546 ensure_time_axis_view_is_visible (*tv, false);
5551 Editor::sync_track_view_list_and_routes ()
5553 track_views = TrackViewList (_routes->views ());
5555 _summary->set_background_dirty();
5556 _group_tabs->set_dirty ();
5558 return false; // do not call again (until needed)
5562 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5564 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5569 /** Find a StripableTimeAxisView by the ID of its stripable */
5570 StripableTimeAxisView*
5571 Editor::get_stripable_time_axis_by_id (const PBD::ID& id) const
5573 StripableTimeAxisView* v;
5575 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5576 if((v = dynamic_cast<StripableTimeAxisView*>(*i)) != 0) {
5577 if(v->stripable()->id() == id) {
5587 Editor::fit_route_group (RouteGroup *g)
5589 TrackViewList ts = axis_views_from_routes (g->route_list ());
5594 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5596 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5599 _session->cancel_audition ();
5603 if (_session->is_auditioning()) {
5604 _session->cancel_audition ();
5605 if (r == last_audition_region) {
5610 _session->audition_region (r);
5611 last_audition_region = r;
5616 Editor::hide_a_region (boost::shared_ptr<Region> r)
5618 r->set_hidden (true);
5622 Editor::show_a_region (boost::shared_ptr<Region> r)
5624 r->set_hidden (false);
5628 Editor::audition_region_from_region_list ()
5630 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5634 Editor::hide_region_from_region_list ()
5636 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5640 Editor::show_region_in_region_list ()
5642 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5646 Editor::step_edit_status_change (bool yn)
5649 start_step_editing ();
5651 stop_step_editing ();
5656 Editor::start_step_editing ()
5658 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5662 Editor::stop_step_editing ()
5664 step_edit_connection.disconnect ();
5668 Editor::check_step_edit ()
5670 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5671 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5673 mtv->check_step_edit ();
5677 return true; // do it again, till we stop
5681 Editor::scroll_press (Direction dir)
5683 ++_scroll_callbacks;
5685 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5686 /* delay the first auto-repeat */
5692 scroll_backward (1);
5700 scroll_up_one_track ();
5704 scroll_down_one_track ();
5708 /* do hacky auto-repeat */
5709 if (!_scroll_connection.connected ()) {
5711 _scroll_connection = Glib::signal_timeout().connect (
5712 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5715 _scroll_callbacks = 0;
5722 Editor::scroll_release ()
5724 _scroll_connection.disconnect ();
5727 /** Queue a change for the Editor viewport x origin to follow the playhead */
5729 Editor::reset_x_origin_to_follow_playhead ()
5731 samplepos_t const sample = playhead_cursor->current_sample ();
5733 if (sample < _leftmost_sample || sample > _leftmost_sample + current_page_samples()) {
5735 if (_session->transport_speed() < 0) {
5737 if (sample > (current_page_samples() / 2)) {
5738 center_screen (sample-(current_page_samples()/2));
5740 center_screen (current_page_samples()/2);
5747 if (sample < _leftmost_sample) {
5749 if (_session->transport_rolling()) {
5750 /* rolling; end up with the playhead at the right of the page */
5751 l = sample - current_page_samples ();
5753 /* not rolling: end up with the playhead 1/4 of the way along the page */
5754 l = sample - current_page_samples() / 4;
5758 if (_session->transport_rolling()) {
5759 /* rolling: end up with the playhead on the left of the page */
5762 /* not rolling: end up with the playhead 3/4 of the way along the page */
5763 l = sample - 3 * current_page_samples() / 4;
5771 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5777 Editor::super_rapid_screen_update ()
5779 if (!_session || !_session->engine().running()) {
5783 /* METERING / MIXER STRIPS */
5785 /* update track meters, if required */
5786 if (contents().is_mapped() && meters_running) {
5787 RouteTimeAxisView* rtv;
5788 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5789 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5790 rtv->fast_update ();
5795 /* and any current mixer strip */
5796 if (current_mixer_strip) {
5797 current_mixer_strip->fast_update ();
5800 /* PLAYHEAD AND VIEWPORT */
5802 /* There are a few reasons why we might not update the playhead / viewport stuff:
5804 * 1. we don't update things when there's a pending locate request, otherwise
5805 * when the editor requests a locate there is a chance that this method
5806 * will move the playhead before the locate request is processed, causing
5808 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5809 * 3. if we're still at the same sample that we were last time, there's nothing to do.
5811 if (_pending_locate_request || !_session->transport_rolling ()) {
5812 _last_update_time = 0;
5816 if (_dragging_playhead) {
5817 _last_update_time = 0;
5821 bool latent_locate = false;
5822 samplepos_t sample = _session->audible_sample (&latent_locate);
5823 const int64_t now = g_get_monotonic_time ();
5826 if (_session->exporting ()) {
5827 /* freewheel/export may be faster or slower than transport_speed() / SR.
5828 * Also exporting multiple ranges locates/jumps without a _pending_locate_request.
5830 _last_update_time = 0;
5833 if (_last_update_time > 0) {
5834 /* interpolate and smoothen playhead position */
5835 const double ds = (now - _last_update_time) * _session->transport_speed() * _session->nominal_sample_rate () * 1e-6;
5836 samplepos_t guess = playhead_cursor->current_sample () + rint (ds);
5837 err = sample - guess;
5839 guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update)
5840 _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2
5843 printf ("eng: %ld gui:%ld (%+6.1f) diff: %6.1f (err: %7.2f)\n",
5845 err, _err_screen_engine);
5850 _err_screen_engine = 0;
5853 if (err > 8192 || latent_locate) {
5854 // in case of x-runs or freewheeling
5855 _last_update_time = 0;
5856 sample = _session->audible_sample ();
5858 _last_update_time = now;
5861 if (playhead_cursor->current_sample () == sample) {
5865 playhead_cursor->set_position (sample);
5867 if (_session->requested_return_sample() >= 0) {
5868 _last_update_time = 0;
5872 if (!_follow_playhead || pending_visual_change.being_handled) {
5873 /* We only do this if we aren't already
5874 * handling a visual change (ie if
5875 * pending_visual_change.being_handled is
5876 * false) so that these requests don't stack
5877 * up there are too many of them to handle in
5883 if (!_stationary_playhead) {
5884 reset_x_origin_to_follow_playhead ();
5886 samplepos_t const sample = playhead_cursor->current_sample ();
5887 double target = ((double)sample - (double)current_page_samples() / 2.0);
5888 if (target <= 0.0) {
5891 // compare to EditorCursor::set_position()
5892 double const old_pos = sample_to_pixel_unrounded (_leftmost_sample);
5893 double const new_pos = sample_to_pixel_unrounded (target);
5894 if (rint (new_pos) != rint (old_pos)) {
5895 reset_x_origin (pixel_to_sample (new_pos));
5902 Editor::session_going_away ()
5904 _have_idled = false;
5906 _session_connections.drop_connections ();
5908 super_rapid_screen_update_connection.disconnect ();
5910 selection->clear ();
5911 cut_buffer->clear ();
5913 clicked_regionview = 0;
5914 clicked_axisview = 0;
5915 clicked_routeview = 0;
5916 entered_regionview = 0;
5918 _last_update_time = 0;
5921 playhead_cursor->hide ();
5923 /* rip everything out of the list displays */
5927 _route_groups->clear ();
5929 /* do this first so that deleting a track doesn't reset cms to null
5930 and thus cause a leak.
5933 if (current_mixer_strip) {
5934 if (current_mixer_strip->get_parent() != 0) {
5935 global_hpacker.remove (*current_mixer_strip);
5937 delete current_mixer_strip;
5938 current_mixer_strip = 0;
5941 /* delete all trackviews */
5943 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5946 track_views.clear ();
5948 nudge_clock->set_session (0);
5950 editor_list_button.set_active(false);
5951 editor_list_button.set_sensitive(false);
5953 /* clear tempo/meter rulers */
5954 remove_metric_marks ();
5956 clear_marker_display ();
5961 stop_step_editing ();
5965 /* get rid of any existing editor mixer strip */
5967 WindowTitle title(Glib::get_application_name());
5968 title += _("Editor");
5970 own_window()->set_title (title.get_string());
5973 SessionHandlePtr::session_going_away ();
5977 Editor::trigger_script (int i)
5979 LuaInstance::instance()-> call_action (i);
5983 Editor::show_editor_list (bool yn)
5986 _editor_list_vbox.show ();
5988 _editor_list_vbox.hide ();
5993 Editor::change_region_layering_order (bool from_context_menu)
5995 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5997 if (!clicked_routeview) {
5998 if (layering_order_editor) {
5999 layering_order_editor->hide ();
6004 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
6010 boost::shared_ptr<Playlist> pl = track->playlist();
6016 if (layering_order_editor == 0) {
6017 layering_order_editor = new RegionLayeringOrderEditor (*this);
6020 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
6021 layering_order_editor->maybe_present ();
6025 Editor::update_region_layering_order_editor ()
6027 if (layering_order_editor && layering_order_editor->is_visible ()) {
6028 change_region_layering_order (true);
6033 Editor::setup_fade_images ()
6035 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
6036 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
6037 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
6038 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
6039 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
6041 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
6042 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
6043 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
6044 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
6045 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
6049 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
6051 Editor::action_menu_item (std::string const & name)
6053 Glib::RefPtr<Action> a = editor_actions->get_action (name);
6056 return *manage (a->create_menu_item ());
6060 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
6062 EventBox* b = manage (new EventBox);
6063 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
6064 Label* l = manage (new Label (name));
6068 _the_notebook.append_page (widget, *b);
6072 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6074 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6075 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6078 if (ev->type == GDK_2BUTTON_PRESS) {
6080 /* double-click on a notebook tab shrinks or expands the notebook */
6082 if (_notebook_shrunk) {
6083 if (pre_notebook_shrink_pane_width) {
6084 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6086 _notebook_shrunk = false;
6088 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6090 /* this expands the LHS of the edit pane to cover the notebook
6091 PAGE but leaves the tabs visible.
6093 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6094 _notebook_shrunk = true;
6102 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6104 using namespace Menu_Helpers;
6106 MenuList& items = _control_point_context_menu.items ();
6109 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6110 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6111 if (!can_remove_control_point (item)) {
6112 items.back().set_sensitive (false);
6115 _control_point_context_menu.popup (event->button.button, event->button.time);
6119 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6121 using namespace Menu_Helpers;
6123 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6128 /* We need to get the selection here and pass it to the operations, since
6129 popping up the menu will cause a region leave event which clears
6130 entered_regionview. */
6132 MidiRegionView& mrv = note->region_view();
6133 const RegionSelection rs = get_regions_from_selection_and_entered ();
6134 const uint32_t sel_size = mrv.selection_size ();
6136 MenuList& items = _note_context_menu.items();
6140 items.push_back(MenuElem(_("Delete"),
6141 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6144 items.push_back(MenuElem(_("Edit..."),
6145 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6146 if (sel_size != 1) {
6147 items.back().set_sensitive (false);
6150 items.push_back(MenuElem(_("Transpose..."),
6151 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6154 items.push_back(MenuElem(_("Legatize"),
6155 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6157 items.back().set_sensitive (false);
6160 items.push_back(MenuElem(_("Quantize..."),
6161 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6163 items.push_back(MenuElem(_("Remove Overlap"),
6164 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6166 items.back().set_sensitive (false);
6169 items.push_back(MenuElem(_("Transform..."),
6170 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6172 _note_context_menu.popup (event->button.button, event->button.time);
6176 Editor::zoom_vertical_modifier_released()
6178 _stepping_axis_view = 0;
6182 Editor::ui_parameter_changed (string parameter)
6184 if (parameter == "icon-set") {
6185 while (!_cursor_stack.empty()) {
6186 _cursor_stack.pop_back();
6188 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6189 _cursor_stack.push_back(_cursors->grabber);
6190 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6191 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6193 } else if (parameter == "draggable-playhead") {
6194 if (_verbose_cursor) {
6195 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6201 Editor::use_own_window (bool and_fill_it)
6203 bool new_window = !own_window();
6205 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6207 if (win && new_window) {
6208 win->set_name ("EditorWindow");
6210 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6212 // win->signal_realize().connect (*this, &Editor::on_realize);
6213 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6214 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6215 win->set_data ("ardour-bindings", bindings);
6220 DisplaySuspender ds;
6221 contents().show_all ();
6223 /* XXX: this is a bit unfortunate; it would probably
6224 be nicer if we could just call show () above rather
6225 than needing the show_all ()
6228 /* re-hide stuff if necessary */
6229 editor_list_button_toggled ();
6230 parameter_changed ("show-summary");
6231 parameter_changed ("show-group-tabs");
6232 parameter_changed ("show-zoom-tools");
6234 /* now reset all audio_time_axis heights, because widgets might need
6240 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6241 tv = (static_cast<TimeAxisView*>(*i));
6242 tv->reset_height ();
6245 if (current_mixer_strip) {
6246 current_mixer_strip->hide_things ();
6247 current_mixer_strip->parameter_changed ("mixer-element-visibility");