2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/eventboxext.h"
61 #include "gtkmm2ext/grouped_buttons.h"
62 #include "gtkmm2ext/gtk_ui.h"
63 #include <gtkmm2ext/keyboard.h>
64 #include "gtkmm2ext/utils.h"
65 #include "gtkmm2ext/window_title.h"
66 #include "gtkmm2ext/choice.h"
67 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
69 #include "ardour/analysis_graph.h"
70 #include "ardour/audio_track.h"
71 #include "ardour/audioengine.h"
72 #include "ardour/audioregion.h"
73 #include "ardour/lmath.h"
74 #include "ardour/location.h"
75 #include "ardour/profile.h"
76 #include "ardour/route.h"
77 #include "ardour/route_group.h"
78 #include "ardour/session_playlists.h"
79 #include "ardour/tempo.h"
80 #include "ardour/utils.h"
81 #include "ardour/vca_manager.h"
82 #include "ardour/vca.h"
84 #include "canvas/debug.h"
85 #include "canvas/text.h"
87 #include "control_protocol/control_protocol.h"
90 #include "analysis_window.h"
91 #include "ardour_spacer.h"
92 #include "audio_clock.h"
93 #include "audio_region_view.h"
94 #include "audio_streamview.h"
95 #include "audio_time_axis.h"
96 #include "automation_time_axis.h"
97 #include "bundle_manager.h"
98 #include "crossfade_edit.h"
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 "tooltips.h"
141 #include "ui_config.h"
143 #include "vca_time_axis.h"
144 #include "verbose_cursor.h"
146 #include "pbd/i18n.h"
149 using namespace ARDOUR;
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)
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_mark_modulo (0)
306 , timecode_nmarks (0)
307 , _samples_ruler_interval (0)
310 , bbt_bar_helper_on (0)
311 , bbt_accent_modulo (0)
316 , visible_timebars (0)
317 , editor_ruler_menu (0)
321 , range_marker_bar (0)
322 , transport_marker_bar (0)
324 , minsec_label (_("Mins:Secs"))
325 , bbt_label (_("Bars:Beats"))
326 , timecode_label (_("Timecode"))
327 , samples_label (_("Samples"))
328 , tempo_label (_("Tempo"))
329 , meter_label (_("Meter"))
330 , mark_label (_("Location Markers"))
331 , range_mark_label (_("Range Markers"))
332 , transport_mark_label (_("Loop/Punch Ranges"))
333 , cd_mark_label (_("CD Markers"))
334 , videotl_label (_("Video Timeline"))
336 , playhead_cursor (0)
337 , edit_packer (4, 4, true)
338 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
339 , horizontal_adjustment (0.0, 0.0, 1e16)
340 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
341 , controls_layout (unused_adjustment, vertical_adjustment)
342 , _scroll_callbacks (0)
343 , _visible_canvas_width (0)
344 , _visible_canvas_height (0)
345 , _full_canvas_height (0)
346 , edit_controls_left_menu (0)
347 , edit_controls_right_menu (0)
348 , visual_change_queued(false)
349 , _last_update_time (0)
350 , _err_screen_engine (0)
351 , cut_buffer_start (0)
352 , cut_buffer_length (0)
353 , button_bindings (0)
357 , current_interthread_info (0)
358 , analysis_window (0)
359 , select_new_marker (false)
361 , scrubbing_direction (0)
362 , scrub_reversals (0)
363 , scrub_reverse_distance (0)
364 , have_pending_keyboard_selection (false)
365 , pending_keyboard_selection_start (0)
366 , _snap_type (SnapToBeat)
367 , _snap_mode (SnapOff)
368 , snap_threshold (5.0)
369 , ignore_gui_changes (false)
370 , _drags (new DragManager (this))
372 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
373 , _dragging_playhead (false)
374 , _dragging_edit_point (false)
375 , _show_measures (true)
376 , _follow_playhead (true)
377 , _stationary_playhead (false)
380 , global_rect_group (0)
381 , time_line_group (0)
382 , tempo_marker_menu (0)
383 , meter_marker_menu (0)
385 , range_marker_menu (0)
386 , transport_marker_menu (0)
387 , new_transport_marker_menu (0)
389 , marker_menu_item (0)
390 , bbt_beat_subdivision (4)
391 , _visible_track_count (-1)
392 , toolbar_selection_clock_table (2,3)
393 , automation_mode_button (_("mode"))
394 , selection (new Selection (this, true))
395 , cut_buffer (new Selection (this, false))
396 , _selection_memento (new SelectionMemento())
397 , _all_region_actions_sensitized (false)
398 , _ignore_region_action (false)
399 , _last_region_menu_was_main (false)
400 , _track_selection_change_without_scroll (false)
401 , cd_marker_bar_drag_rect (0)
402 , range_bar_drag_rect (0)
403 , transport_bar_drag_rect (0)
404 , transport_bar_range_rect (0)
405 , transport_bar_preroll_rect (0)
406 , transport_bar_postroll_rect (0)
407 , transport_loop_range_rect (0)
408 , transport_punch_range_rect (0)
409 , transport_punchin_line (0)
410 , transport_punchout_line (0)
411 , transport_preroll_rect (0)
412 , transport_postroll_rect (0)
414 , rubberband_rect (0)
420 , autoscroll_horizontal_allowed (false)
421 , autoscroll_vertical_allowed (false)
423 , autoscroll_widget (0)
424 , show_gain_after_trim (false)
425 , selection_op_cmd_depth (0)
426 , selection_op_history_it (0)
427 , no_save_instant (false)
429 , current_mixer_strip (0)
430 , show_editor_mixer_when_tracks_arrive (false)
431 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
432 , current_stepping_trackview (0)
433 , last_track_height_step_timestamp (0)
435 , entered_regionview (0)
436 , clear_entered_track (false)
437 , _edit_point (EditAtMouse)
438 , meters_running (false)
440 , _have_idled (false)
441 , resize_idle_id (-1)
442 , _pending_resize_amount (0)
443 , _pending_resize_view (0)
444 , _pending_locate_request (false)
445 , _pending_initial_locate (false)
449 , layering_order_editor (0)
450 , _last_cut_copy_source_track (0)
451 , _region_selection_change_updates_region_list (true)
453 , _following_mixer_selection (false)
454 , _control_point_toggled_on_press (false)
455 , _stepping_axis_view (0)
456 , quantize_dialog (0)
457 , _main_menu_disabler (0)
458 , myactions (X_("editor"))
460 /* we are a singleton */
462 PublicEditor::_instance = this;
466 last_event_time.tv_sec = 0;
467 last_event_time.tv_usec = 0;
469 selection_op_history.clear();
472 snap_type_strings = I18N (_snap_type_strings);
473 snap_mode_strings = I18N (_snap_mode_strings);
474 zoom_focus_strings = I18N (_zoom_focus_strings);
475 edit_mode_strings = I18N (_edit_mode_strings);
476 edit_point_strings = I18N (_edit_point_strings);
477 #ifdef USE_RUBBERBAND
478 rb_opt_strings = I18N (_rb_opt_strings);
482 build_edit_mode_menu();
483 build_zoom_focus_menu();
484 build_track_count_menu();
485 build_snap_mode_menu();
486 build_snap_type_menu();
487 build_edit_point_menu();
489 location_marker_color = UIConfiguration::instance().color ("location marker");
490 location_range_color = UIConfiguration::instance().color ("location range");
491 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
492 location_loop_color = UIConfiguration::instance().color ("location loop");
493 location_punch_color = UIConfiguration::instance().color ("location punch");
495 timebar_height = std::max (12., ceil (15. * UIConfiguration::instance().get_ui_scale()));
497 TimeAxisView::setup_sizes ();
498 ArdourMarker::setup_sizes (timebar_height);
499 TempoCurve::setup_sizes (timebar_height);
501 bbt_label.set_name ("EditorRulerLabel");
502 bbt_label.set_size_request (-1, (int)timebar_height);
503 bbt_label.set_alignment (1.0, 0.5);
504 bbt_label.set_padding (5,0);
506 bbt_label.set_no_show_all();
507 minsec_label.set_name ("EditorRulerLabel");
508 minsec_label.set_size_request (-1, (int)timebar_height);
509 minsec_label.set_alignment (1.0, 0.5);
510 minsec_label.set_padding (5,0);
511 minsec_label.hide ();
512 minsec_label.set_no_show_all();
513 timecode_label.set_name ("EditorRulerLabel");
514 timecode_label.set_size_request (-1, (int)timebar_height);
515 timecode_label.set_alignment (1.0, 0.5);
516 timecode_label.set_padding (5,0);
517 timecode_label.hide ();
518 timecode_label.set_no_show_all();
519 samples_label.set_name ("EditorRulerLabel");
520 samples_label.set_size_request (-1, (int)timebar_height);
521 samples_label.set_alignment (1.0, 0.5);
522 samples_label.set_padding (5,0);
523 samples_label.hide ();
524 samples_label.set_no_show_all();
526 tempo_label.set_name ("EditorRulerLabel");
527 tempo_label.set_size_request (-1, (int)timebar_height);
528 tempo_label.set_alignment (1.0, 0.5);
529 tempo_label.set_padding (5,0);
531 tempo_label.set_no_show_all();
533 meter_label.set_name ("EditorRulerLabel");
534 meter_label.set_size_request (-1, (int)timebar_height);
535 meter_label.set_alignment (1.0, 0.5);
536 meter_label.set_padding (5,0);
538 meter_label.set_no_show_all();
540 if (Profile->get_trx()) {
541 mark_label.set_text (_("Markers"));
543 mark_label.set_name ("EditorRulerLabel");
544 mark_label.set_size_request (-1, (int)timebar_height);
545 mark_label.set_alignment (1.0, 0.5);
546 mark_label.set_padding (5,0);
548 mark_label.set_no_show_all();
550 cd_mark_label.set_name ("EditorRulerLabel");
551 cd_mark_label.set_size_request (-1, (int)timebar_height);
552 cd_mark_label.set_alignment (1.0, 0.5);
553 cd_mark_label.set_padding (5,0);
554 cd_mark_label.hide();
555 cd_mark_label.set_no_show_all();
557 videotl_bar_height = 4;
558 videotl_label.set_name ("EditorRulerLabel");
559 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
560 videotl_label.set_alignment (1.0, 0.5);
561 videotl_label.set_padding (5,0);
562 videotl_label.hide();
563 videotl_label.set_no_show_all();
565 range_mark_label.set_name ("EditorRulerLabel");
566 range_mark_label.set_size_request (-1, (int)timebar_height);
567 range_mark_label.set_alignment (1.0, 0.5);
568 range_mark_label.set_padding (5,0);
569 range_mark_label.hide();
570 range_mark_label.set_no_show_all();
572 transport_mark_label.set_name ("EditorRulerLabel");
573 transport_mark_label.set_size_request (-1, (int)timebar_height);
574 transport_mark_label.set_alignment (1.0, 0.5);
575 transport_mark_label.set_padding (5,0);
576 transport_mark_label.hide();
577 transport_mark_label.set_no_show_all();
579 initialize_canvas ();
581 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
583 _summary = new EditorSummary (this);
585 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
587 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
589 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
590 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
592 edit_controls_vbox.set_spacing (0);
593 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
594 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
596 HBox* h = manage (new HBox);
597 _group_tabs = new EditorGroupTabs (this);
598 if (!ARDOUR::Profile->get_trx()) {
599 h->pack_start (*_group_tabs, PACK_SHRINK);
601 h->pack_start (edit_controls_vbox);
602 controls_layout.add (*h);
604 controls_layout.set_name ("EditControlsBase");
605 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
606 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
607 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
609 _cursors = new MouseCursors;
610 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
611 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
613 /* Push default cursor to ever-present bottom of cursor stack. */
614 push_canvas_cursor(_cursors->grabber);
616 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
618 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
619 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
620 pad_line_1->set_outline_color (0xFF0000FF);
626 edit_packer.set_col_spacings (0);
627 edit_packer.set_row_spacings (0);
628 edit_packer.set_homogeneous (false);
629 edit_packer.set_border_width (0);
630 edit_packer.set_name ("EditorWindow");
632 time_bars_event_box.add (time_bars_vbox);
633 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
634 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
636 /* labels for the time bars */
637 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
639 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
641 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
643 bottom_hbox.set_border_width (2);
644 bottom_hbox.set_spacing (3);
646 PresentationInfo::Change.connect (*this, MISSING_INVALIDATOR, boost::bind (&Editor::presentation_info_changed, this, _1), gui_context());
648 _route_groups = new EditorRouteGroups (this);
649 _routes = new EditorRoutes (this);
650 _regions = new EditorRegions (this);
651 _snapshots = new EditorSnapshots (this);
652 _locations = new EditorLocations (this);
653 _time_info_box = new TimeInfoBox ("EditorTimeInfo", true);
655 /* these are static location signals */
657 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
658 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
659 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
661 add_notebook_page (_("Regions"), _regions->widget ());
662 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
663 add_notebook_page (_("Snapshots"), _snapshots->widget ());
664 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
665 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
667 _the_notebook.set_show_tabs (true);
668 _the_notebook.set_scrollable (true);
669 _the_notebook.popup_disable ();
670 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
671 _the_notebook.show_all ();
673 _notebook_shrunk = false;
676 /* Pick up some settings we need to cache, early */
678 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
681 settings->get_property ("notebook-shrunk", _notebook_shrunk);
684 editor_summary_pane.set_check_divider_position (true);
685 editor_summary_pane.add (edit_packer);
687 Button* summary_arrows_left_left = manage (new Button);
688 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
689 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
690 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
692 Button* summary_arrows_left_right = manage (new Button);
693 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
694 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
695 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
697 VBox* summary_arrows_left = manage (new VBox);
698 summary_arrows_left->pack_start (*summary_arrows_left_left);
699 summary_arrows_left->pack_start (*summary_arrows_left_right);
701 Button* summary_arrows_right_up = manage (new Button);
702 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
703 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
704 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
706 Button* summary_arrows_right_down = manage (new Button);
707 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
708 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
709 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
711 VBox* summary_arrows_right = manage (new VBox);
712 summary_arrows_right->pack_start (*summary_arrows_right_up);
713 summary_arrows_right->pack_start (*summary_arrows_right_down);
715 Frame* summary_frame = manage (new Frame);
716 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
718 summary_frame->add (*_summary);
719 summary_frame->show ();
721 _summary_hbox.pack_start (*summary_arrows_left, false, false);
722 _summary_hbox.pack_start (*summary_frame, true, true);
723 _summary_hbox.pack_start (*summary_arrows_right, false, false);
725 if (!ARDOUR::Profile->get_trx()) {
726 editor_summary_pane.add (_summary_hbox);
729 edit_pane.set_check_divider_position (true);
730 edit_pane.add (editor_summary_pane);
731 if (!ARDOUR::Profile->get_trx()) {
732 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
733 _editor_list_vbox.pack_start (_the_notebook);
734 edit_pane.add (_editor_list_vbox);
735 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
738 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
739 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
742 if (!settings || !settings->get_property ("edit-horizontal-pane-pos", fract) || fract > 1.0) {
743 /* initial allocation is 90% to canvas, 10% to notebook */
746 edit_pane.set_divider (0, fract);
748 if (!settings || !settings->get_property ("edit-vertical-pane-pos", fract) || fract > 1.0) {
749 /* initial allocation is 90% to canvas, 10% to summary */
752 editor_summary_pane.set_divider (0, fract);
754 global_vpacker.set_spacing (2);
755 global_vpacker.set_border_width (0);
757 //the next three EventBoxes provide the ability for their child widgets to have a background color. That is all.
759 Gtk::EventBox* ebox = manage (new Gtk::EventBox); //a themeable box
760 ebox->set_name("EditorWindow");
761 ebox->add (toolbar_hbox);
763 Gtk::EventBox* epane_box = manage (new Gtkmm2ext::EventBoxExt); //a themeable box
764 epane_box->set_name("EditorWindow");
765 epane_box->add (edit_pane);
767 Gtk::EventBox* epane_box2 = manage (new Gtkmm2ext::EventBoxExt); //a themeable box
768 epane_box2->set_name("EditorWindow");
769 epane_box2->add (global_vpacker);
771 global_vpacker.pack_start (*ebox, false, false);
772 global_vpacker.pack_start (*epane_box, true, true);
773 global_hpacker.pack_start (*epane_box2, true, true);
775 /* need to show the "contents" widget so that notebook will show if tab is switched to
778 global_hpacker.show ();
780 /* register actions now so that set_state() can find them and set toggles/checks etc */
787 _playlist_selector = new PlaylistSelector();
788 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
790 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
794 nudge_forward_button.set_name ("nudge button");
795 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
797 nudge_backward_button.set_name ("nudge button");
798 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
800 fade_context_menu.set_name ("ArdourContextMenu");
802 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
804 /* allow external control surfaces/protocols to do various things */
806 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
807 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
808 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
809 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
810 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
811 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
812 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
813 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
814 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
815 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
816 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
817 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
818 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
819 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
821 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
822 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
823 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
824 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
825 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
827 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
831 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
833 /* problematic: has to return a value and thus cannot be x-thread */
835 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
837 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
838 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
840 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
842 _ignore_region_action = false;
843 _last_region_menu_was_main = false;
844 _popup_region_menu_item = 0;
846 _show_marker_lines = false;
848 /* Button bindings */
850 button_bindings = new Bindings ("editor-mouse");
852 XMLNode* node = button_settings();
854 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
855 button_bindings->load_operation (**i);
861 /* grab current parameter state */
862 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
863 UIConfiguration::instance().map_parameters (pc);
865 setup_fade_images ();
872 delete button_bindings;
874 delete _route_groups;
875 delete _track_canvas_viewport;
878 delete _verbose_cursor;
879 delete quantize_dialog;
885 delete _playlist_selector;
886 delete _time_info_box;
891 LuaInstance::destroy_instance ();
893 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
896 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_in_images.begin(); i != _xfade_in_images.end (); ++i) {
899 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_out_images.begin(); i != _xfade_out_images.end (); ++i) {
905 Editor::button_settings () const
907 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
908 XMLNode* node = find_named_node (*settings, X_("Buttons"));
911 node = new XMLNode (X_("Buttons"));
918 Editor::get_smart_mode () const
920 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
924 Editor::catch_vanishing_regionview (RegionView *rv)
926 /* note: the selection will take care of the vanishing
927 audioregionview by itself.
930 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
934 if (clicked_regionview == rv) {
935 clicked_regionview = 0;
938 if (entered_regionview == rv) {
939 set_entered_regionview (0);
942 if (!_all_region_actions_sensitized) {
943 sensitize_all_region_actions (true);
948 Editor::set_entered_regionview (RegionView* rv)
950 if (rv == entered_regionview) {
954 if (entered_regionview) {
955 entered_regionview->exited ();
958 entered_regionview = rv;
960 if (entered_regionview != 0) {
961 entered_regionview->entered ();
964 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
965 /* This RegionView entry might have changed what region actions
966 are allowed, so sensitize them all in case a key is pressed.
968 sensitize_all_region_actions (true);
973 Editor::set_entered_track (TimeAxisView* tav)
976 entered_track->exited ();
982 entered_track->entered ();
987 Editor::instant_save ()
989 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
994 _session->add_instant_xml(get_state());
996 Config->add_instant_xml(get_state());
1001 Editor::control_vertical_zoom_in_all ()
1003 tav_zoom_smooth (false, true);
1007 Editor::control_vertical_zoom_out_all ()
1009 tav_zoom_smooth (true, true);
1013 Editor::control_vertical_zoom_in_selected ()
1015 tav_zoom_smooth (false, false);
1019 Editor::control_vertical_zoom_out_selected ()
1021 tav_zoom_smooth (true, false);
1025 Editor::control_view (uint32_t view)
1027 goto_visual_state (view);
1031 Editor::control_unselect ()
1033 selection->clear_tracks ();
1037 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1039 TimeAxisView* tav = time_axis_view_from_stripable (s);
1043 case Selection::Add:
1044 selection->add (tav);
1046 case Selection::Toggle:
1047 selection->toggle (tav);
1049 case Selection::Extend:
1051 case Selection::Set:
1052 selection->set (tav);
1056 selection->clear_tracks ();
1061 Editor::control_step_tracks_up ()
1063 scroll_tracks_up_line ();
1067 Editor::control_step_tracks_down ()
1069 scroll_tracks_down_line ();
1073 Editor::control_scroll (float fraction)
1075 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1081 double step = fraction * current_page_samples();
1084 _control_scroll_target is an optional<T>
1086 it acts like a pointer to an framepos_t, with
1087 a operator conversion to boolean to check
1088 that it has a value could possibly use
1089 playhead_cursor->current_frame to store the
1090 value and a boolean in the class to know
1091 when it's out of date
1094 if (!_control_scroll_target) {
1095 _control_scroll_target = _session->transport_frame();
1096 _dragging_playhead = true;
1099 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1100 *_control_scroll_target = 0;
1101 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1102 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1104 *_control_scroll_target += (framepos_t) trunc (step);
1107 /* move visuals, we'll catch up with it later */
1109 playhead_cursor->set_position (*_control_scroll_target);
1110 UpdateAllTransportClocks (*_control_scroll_target);
1112 if (*_control_scroll_target > (current_page_samples() / 2)) {
1113 /* try to center PH in window */
1114 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1120 Now we do a timeout to actually bring the session to the right place
1121 according to the playhead. This is to avoid reading disk buffers on every
1122 call to control_scroll, which is driven by ScrollTimeline and therefore
1123 probably by a control surface wheel which can generate lots of events.
1125 /* cancel the existing timeout */
1127 control_scroll_connection.disconnect ();
1129 /* add the next timeout */
1131 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1135 Editor::deferred_control_scroll (framepos_t /*target*/)
1137 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1138 // reset for next stream
1139 _control_scroll_target = boost::none;
1140 _dragging_playhead = false;
1145 Editor::access_action (std::string action_group, std::string action_item)
1151 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1154 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1162 Editor::on_realize ()
1166 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1167 start_lock_event_timing ();
1172 Editor::start_lock_event_timing ()
1174 /* check if we should lock the GUI every 30 seconds */
1176 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1180 Editor::generic_event_handler (GdkEvent* ev)
1183 case GDK_BUTTON_PRESS:
1184 case GDK_BUTTON_RELEASE:
1185 case GDK_MOTION_NOTIFY:
1187 case GDK_KEY_RELEASE:
1188 if (contents().is_mapped()) {
1189 gettimeofday (&last_event_time, 0);
1193 case GDK_LEAVE_NOTIFY:
1194 switch (ev->crossing.detail) {
1195 case GDK_NOTIFY_UNKNOWN:
1196 case GDK_NOTIFY_INFERIOR:
1197 case GDK_NOTIFY_ANCESTOR:
1199 case GDK_NOTIFY_VIRTUAL:
1200 case GDK_NOTIFY_NONLINEAR:
1201 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1202 /* leaving window, so reset focus, thus ending any and
1203 all text entry operations.
1205 ARDOUR_UI::instance()->reset_focus (&contents());
1218 Editor::lock_timeout_callback ()
1220 struct timeval now, delta;
1222 gettimeofday (&now, 0);
1224 timersub (&now, &last_event_time, &delta);
1226 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1228 /* don't call again. Returning false will effectively
1229 disconnect us from the timer callback.
1231 unlock() will call start_lock_event_timing() to get things
1241 Editor::map_position_change (framepos_t frame)
1243 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1245 if (_session == 0) {
1249 if (_follow_playhead) {
1250 center_screen (frame);
1253 playhead_cursor->set_position (frame);
1257 Editor::center_screen (framepos_t frame)
1259 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1261 /* if we're off the page, then scroll.
1264 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1265 center_screen_internal (frame, page);
1270 Editor::center_screen_internal (framepos_t frame, float page)
1275 frame -= (framepos_t) page;
1280 reset_x_origin (frame);
1285 Editor::update_title ()
1287 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1289 if (!own_window()) {
1294 bool dirty = _session->dirty();
1296 string session_name;
1298 if (_session->snap_name() != _session->name()) {
1299 session_name = _session->snap_name();
1301 session_name = _session->name();
1305 session_name = "*" + session_name;
1308 WindowTitle title(session_name);
1309 title += S_("Window|Editor");
1310 title += Glib::get_application_name();
1311 own_window()->set_title (title.get_string());
1313 /* ::session_going_away() will have taken care of it */
1318 Editor::set_session (Session *t)
1320 SessionHandlePtr::set_session (t);
1326 _playlist_selector->set_session (_session);
1327 nudge_clock->set_session (_session);
1328 _summary->set_session (_session);
1329 _group_tabs->set_session (_session);
1330 _route_groups->set_session (_session);
1331 _regions->set_session (_session);
1332 _snapshots->set_session (_session);
1333 _routes->set_session (_session);
1334 _locations->set_session (_session);
1335 _time_info_box->set_session (_session);
1337 if (rhythm_ferret) {
1338 rhythm_ferret->set_session (_session);
1341 if (analysis_window) {
1342 analysis_window->set_session (_session);
1346 sfbrowser->set_session (_session);
1349 compute_fixed_ruler_scale ();
1351 /* Make sure we have auto loop and auto punch ranges */
1353 Location* loc = _session->locations()->auto_loop_location();
1355 loc->set_name (_("Loop"));
1358 loc = _session->locations()->auto_punch_location();
1361 loc->set_name (_("Punch"));
1364 refresh_location_display ();
1366 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1367 the selected Marker; this needs the LocationMarker list to be available.
1369 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1370 set_state (*node, Stateful::loading_state_version);
1372 /* catch up on selection state, etc. */
1375 sc.add (Properties::selected);
1376 presentation_info_changed (sc);
1378 /* catch up with the playhead */
1380 _session->request_locate (playhead_cursor->current_frame ());
1381 _pending_initial_locate = true;
1385 /* These signals can all be emitted by a non-GUI thread. Therefore the
1386 handlers for them must not attempt to directly interact with the GUI,
1387 but use PBD::Signal<T>::connect() which accepts an event loop
1388 ("context") where the handler will be asked to run.
1391 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1392 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1393 _session->TransportLooped.connect (_session_connections, invalidator (*this), boost::bind (&Editor::transport_looped, this), gui_context());
1394 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1395 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1396 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1397 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1398 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1399 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1400 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1401 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1402 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1403 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1404 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1405 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1406 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1408 playhead_cursor->show ();
1410 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1411 Config->map_parameters (pc);
1412 _session->config.map_parameters (pc);
1414 restore_ruler_visibility ();
1415 //tempo_map_changed (PropertyChange (0));
1416 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1418 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1419 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1422 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1423 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1426 switch (_snap_type) {
1427 case SnapToRegionStart:
1428 case SnapToRegionEnd:
1429 case SnapToRegionSync:
1430 case SnapToRegionBoundary:
1431 build_region_boundary_cache ();
1438 /* register for undo history */
1439 _session->register_with_memento_command_factory(id(), this);
1440 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1442 LuaInstance::instance()->set_session(_session);
1444 start_updating_meters ();
1448 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1450 using namespace Menu_Helpers;
1452 void (Editor::*emf)(FadeShape);
1453 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1456 images = &_xfade_in_images;
1457 emf = &Editor::set_fade_in_shape;
1459 images = &_xfade_out_images;
1460 emf = &Editor::set_fade_out_shape;
1465 _("Linear (for highly correlated material)"),
1466 *(*images)[FadeLinear],
1467 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1471 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1475 _("Constant power"),
1476 *(*images)[FadeConstantPower],
1477 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1480 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1485 *(*images)[FadeSymmetric],
1486 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1490 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1495 *(*images)[FadeSlow],
1496 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1499 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1504 *(*images)[FadeFast],
1505 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1508 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1511 /** Pop up a context menu for when the user clicks on a start crossfade */
1513 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1515 using namespace Menu_Helpers;
1516 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1521 MenuList& items (xfade_in_context_menu.items());
1524 if (arv->audio_region()->fade_in_active()) {
1525 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1527 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1530 items.push_back (SeparatorElem());
1531 fill_xfade_menu (items, true);
1533 xfade_in_context_menu.popup (button, time);
1536 /** Pop up a context menu for when the user clicks on an end crossfade */
1538 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1540 using namespace Menu_Helpers;
1541 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1546 MenuList& items (xfade_out_context_menu.items());
1549 if (arv->audio_region()->fade_out_active()) {
1550 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1552 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1555 items.push_back (SeparatorElem());
1556 fill_xfade_menu (items, false);
1558 xfade_out_context_menu.popup (button, time);
1562 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1564 using namespace Menu_Helpers;
1565 Menu* (Editor::*build_menu_function)();
1568 switch (item_type) {
1570 case RegionViewName:
1571 case RegionViewNameHighlight:
1572 case LeftFrameHandle:
1573 case RightFrameHandle:
1574 if (with_selection) {
1575 build_menu_function = &Editor::build_track_selection_context_menu;
1577 build_menu_function = &Editor::build_track_region_context_menu;
1582 if (with_selection) {
1583 build_menu_function = &Editor::build_track_selection_context_menu;
1585 build_menu_function = &Editor::build_track_context_menu;
1590 if (clicked_routeview->track()) {
1591 build_menu_function = &Editor::build_track_context_menu;
1593 build_menu_function = &Editor::build_track_bus_context_menu;
1598 /* probably shouldn't happen but if it does, we don't care */
1602 menu = (this->*build_menu_function)();
1603 menu->set_name ("ArdourContextMenu");
1605 /* now handle specific situations */
1607 switch (item_type) {
1609 case RegionViewName:
1610 case RegionViewNameHighlight:
1611 case LeftFrameHandle:
1612 case RightFrameHandle:
1613 if (!with_selection) {
1614 if (region_edit_menu_split_item) {
1615 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1616 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1618 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1621 if (region_edit_menu_split_multichannel_item) {
1622 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1623 region_edit_menu_split_multichannel_item->set_sensitive (true);
1625 region_edit_menu_split_multichannel_item->set_sensitive (false);
1638 /* probably shouldn't happen but if it does, we don't care */
1642 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1644 /* Bounce to disk */
1646 using namespace Menu_Helpers;
1647 MenuList& edit_items = menu->items();
1649 edit_items.push_back (SeparatorElem());
1651 switch (clicked_routeview->audio_track()->freeze_state()) {
1652 case AudioTrack::NoFreeze:
1653 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1656 case AudioTrack::Frozen:
1657 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1660 case AudioTrack::UnFrozen:
1661 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1667 if (item_type == StreamItem && clicked_routeview) {
1668 clicked_routeview->build_underlay_menu(menu);
1671 /* When the region menu is opened, we setup the actions so that they look right
1674 sensitize_the_right_region_actions (false);
1675 _last_region_menu_was_main = false;
1677 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1678 menu->popup (button, time);
1682 Editor::build_track_context_menu ()
1684 using namespace Menu_Helpers;
1686 MenuList& edit_items = track_context_menu.items();
1689 add_dstream_context_items (edit_items);
1690 return &track_context_menu;
1694 Editor::build_track_bus_context_menu ()
1696 using namespace Menu_Helpers;
1698 MenuList& edit_items = track_context_menu.items();
1701 add_bus_context_items (edit_items);
1702 return &track_context_menu;
1706 Editor::build_track_region_context_menu ()
1708 using namespace Menu_Helpers;
1709 MenuList& edit_items = track_region_context_menu.items();
1712 /* we've just cleared the track region context menu, so the menu that these
1713 two items were on will have disappeared; stop them dangling.
1715 region_edit_menu_split_item = 0;
1716 region_edit_menu_split_multichannel_item = 0;
1718 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1721 boost::shared_ptr<Track> tr;
1722 boost::shared_ptr<Playlist> pl;
1724 if ((tr = rtv->track())) {
1725 add_region_context_items (edit_items, tr);
1729 add_dstream_context_items (edit_items);
1731 return &track_region_context_menu;
1735 Editor::loudness_analyze_region_selection ()
1740 Selection& s (PublicEditor::instance ().get_selection ());
1741 RegionSelection ars = s.regions;
1742 ARDOUR::AnalysisGraph ag (_session);
1743 framecnt_t total_work = 0;
1745 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1746 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1750 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1753 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1754 total_work += arv->region ()->length ();
1757 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1759 ag.set_total_frames (total_work);
1760 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1763 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1764 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1768 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1772 ag.analyze_region (ar);
1775 if (!ag.canceled ()) {
1776 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1782 Editor::loudness_analyze_range_selection ()
1787 Selection& s (PublicEditor::instance ().get_selection ());
1788 TimeSelection ts = s.time;
1789 ARDOUR::AnalysisGraph ag (_session);
1790 framecnt_t total_work = 0;
1792 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1793 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1797 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1801 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1802 total_work += j->length ();
1806 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1808 ag.set_total_frames (total_work);
1809 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1812 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1813 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1817 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1821 ag.analyze_range (rui->route (), pl, ts);
1824 if (!ag.canceled ()) {
1825 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1831 Editor::spectral_analyze_region_selection ()
1833 if (analysis_window == 0) {
1834 analysis_window = new AnalysisWindow();
1837 analysis_window->set_session(_session);
1839 analysis_window->show_all();
1842 analysis_window->set_regionmode();
1843 analysis_window->analyze();
1845 analysis_window->present();
1849 Editor::spectral_analyze_range_selection()
1851 if (analysis_window == 0) {
1852 analysis_window = new AnalysisWindow();
1855 analysis_window->set_session(_session);
1857 analysis_window->show_all();
1860 analysis_window->set_rangemode();
1861 analysis_window->analyze();
1863 analysis_window->present();
1867 Editor::build_track_selection_context_menu ()
1869 using namespace Menu_Helpers;
1870 MenuList& edit_items = track_selection_context_menu.items();
1871 edit_items.clear ();
1873 add_selection_context_items (edit_items);
1874 // edit_items.push_back (SeparatorElem());
1875 // add_dstream_context_items (edit_items);
1877 return &track_selection_context_menu;
1881 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1883 using namespace Menu_Helpers;
1885 /* OK, stick the region submenu at the top of the list, and then add
1889 RegionSelection rs = get_regions_from_selection_and_entered ();
1891 string::size_type pos = 0;
1892 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1894 /* we have to hack up the region name because "_" has a special
1895 meaning for menu titles.
1898 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1899 menu_item_name.replace (pos, 1, "__");
1903 if (_popup_region_menu_item == 0) {
1904 _popup_region_menu_item = new MenuItem (menu_item_name);
1905 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1906 _popup_region_menu_item->show ();
1908 _popup_region_menu_item->set_label (menu_item_name);
1911 /* No layering allowed in later is higher layering model */
1912 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1913 if (act && Config->get_layer_model() == LaterHigher) {
1914 act->set_sensitive (false);
1916 act->set_sensitive (true);
1919 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1921 edit_items.push_back (*_popup_region_menu_item);
1922 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1923 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1925 edit_items.push_back (SeparatorElem());
1928 /** Add context menu items relevant to selection ranges.
1929 * @param edit_items List to add the items to.
1932 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1934 using namespace Menu_Helpers;
1936 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1937 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1939 edit_items.push_back (SeparatorElem());
1940 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1942 edit_items.push_back (SeparatorElem());
1943 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1944 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1946 edit_items.push_back (SeparatorElem());
1948 edit_items.push_back (
1950 _("Move Range Start to Previous Region Boundary"),
1951 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1955 edit_items.push_back (
1957 _("Move Range Start to Next Region Boundary"),
1958 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1962 edit_items.push_back (
1964 _("Move Range End to Previous Region Boundary"),
1965 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1969 edit_items.push_back (
1971 _("Move Range End to Next Region Boundary"),
1972 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1976 edit_items.push_back (SeparatorElem());
1977 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1978 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1980 edit_items.push_back (SeparatorElem());
1981 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1983 edit_items.push_back (SeparatorElem());
1984 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1985 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1986 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1988 edit_items.push_back (SeparatorElem());
1989 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1991 edit_items.push_back (SeparatorElem());
1992 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1993 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1995 edit_items.push_back (SeparatorElem());
1996 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1997 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1998 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1999 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
2000 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
2001 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
2002 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2008 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2010 using namespace Menu_Helpers;
2014 Menu *play_menu = manage (new Menu);
2015 MenuList& play_items = play_menu->items();
2016 play_menu->set_name ("ArdourContextMenu");
2018 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2019 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2020 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2021 play_items.push_back (SeparatorElem());
2022 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2024 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2028 Menu *select_menu = manage (new Menu);
2029 MenuList& select_items = select_menu->items();
2030 select_menu->set_name ("ArdourContextMenu");
2032 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2033 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2034 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2035 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2036 select_items.push_back (SeparatorElem());
2037 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2038 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2039 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2040 select_items.push_back (SeparatorElem());
2041 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2042 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2043 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2044 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2045 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2046 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2047 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2049 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2053 Menu *cutnpaste_menu = manage (new Menu);
2054 MenuList& cutnpaste_items = cutnpaste_menu->items();
2055 cutnpaste_menu->set_name ("ArdourContextMenu");
2057 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2058 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2059 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2061 cutnpaste_items.push_back (SeparatorElem());
2063 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2064 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2066 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2068 /* Adding new material */
2070 edit_items.push_back (SeparatorElem());
2071 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2072 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2076 Menu *nudge_menu = manage (new Menu());
2077 MenuList& nudge_items = nudge_menu->items();
2078 nudge_menu->set_name ("ArdourContextMenu");
2080 edit_items.push_back (SeparatorElem());
2081 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2082 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2083 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2084 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2086 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2090 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2092 using namespace Menu_Helpers;
2096 Menu *play_menu = manage (new Menu);
2097 MenuList& play_items = play_menu->items();
2098 play_menu->set_name ("ArdourContextMenu");
2100 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2101 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2102 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2106 Menu *select_menu = manage (new Menu);
2107 MenuList& select_items = select_menu->items();
2108 select_menu->set_name ("ArdourContextMenu");
2110 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2111 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2112 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2113 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2114 select_items.push_back (SeparatorElem());
2115 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2116 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2117 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2118 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2120 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2124 Menu *cutnpaste_menu = manage (new Menu);
2125 MenuList& cutnpaste_items = cutnpaste_menu->items();
2126 cutnpaste_menu->set_name ("ArdourContextMenu");
2128 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2129 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2130 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2132 Menu *nudge_menu = manage (new Menu());
2133 MenuList& nudge_items = nudge_menu->items();
2134 nudge_menu->set_name ("ArdourContextMenu");
2136 edit_items.push_back (SeparatorElem());
2137 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2138 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2139 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2140 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2142 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2146 Editor::snap_type() const
2152 Editor::snap_musical() const
2154 switch (_snap_type) {
2155 case SnapToBeatDiv128:
2156 case SnapToBeatDiv64:
2157 case SnapToBeatDiv32:
2158 case SnapToBeatDiv28:
2159 case SnapToBeatDiv24:
2160 case SnapToBeatDiv20:
2161 case SnapToBeatDiv16:
2162 case SnapToBeatDiv14:
2163 case SnapToBeatDiv12:
2164 case SnapToBeatDiv10:
2165 case SnapToBeatDiv8:
2166 case SnapToBeatDiv7:
2167 case SnapToBeatDiv6:
2168 case SnapToBeatDiv5:
2169 case SnapToBeatDiv4:
2170 case SnapToBeatDiv3:
2171 case SnapToBeatDiv2:
2183 Editor::snap_mode() const
2189 Editor::set_snap_to (SnapType st)
2191 unsigned int snap_ind = (unsigned int)st;
2193 if (internal_editing()) {
2194 internal_snap_type = st;
2196 pre_internal_snap_type = st;
2201 if (snap_ind > snap_type_strings.size() - 1) {
2203 _snap_type = (SnapType)snap_ind;
2206 string str = snap_type_strings[snap_ind];
2208 if (str != snap_type_selector.get_text()) {
2209 snap_type_selector.set_text (str);
2214 switch (_snap_type) {
2215 case SnapToBeatDiv128:
2216 case SnapToBeatDiv64:
2217 case SnapToBeatDiv32:
2218 case SnapToBeatDiv28:
2219 case SnapToBeatDiv24:
2220 case SnapToBeatDiv20:
2221 case SnapToBeatDiv16:
2222 case SnapToBeatDiv14:
2223 case SnapToBeatDiv12:
2224 case SnapToBeatDiv10:
2225 case SnapToBeatDiv8:
2226 case SnapToBeatDiv7:
2227 case SnapToBeatDiv6:
2228 case SnapToBeatDiv5:
2229 case SnapToBeatDiv4:
2230 case SnapToBeatDiv3:
2231 case SnapToBeatDiv2: {
2232 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
2233 update_tempo_based_rulers ();
2237 case SnapToRegionStart:
2238 case SnapToRegionEnd:
2239 case SnapToRegionSync:
2240 case SnapToRegionBoundary:
2241 build_region_boundary_cache ();
2249 redisplay_tempo (false);
2251 SnapChanged (); /* EMIT SIGNAL */
2255 Editor::set_snap_mode (SnapMode mode)
2257 string str = snap_mode_strings[(int)mode];
2259 if (internal_editing()) {
2260 internal_snap_mode = mode;
2262 pre_internal_snap_mode = mode;
2267 if (str != snap_mode_selector.get_text ()) {
2268 snap_mode_selector.set_text (str);
2275 Editor::set_edit_point_preference (EditPoint ep, bool force)
2277 bool changed = (_edit_point != ep);
2280 if (Profile->get_mixbus())
2281 if (ep == EditAtSelectedMarker)
2282 ep = EditAtPlayhead;
2284 string str = edit_point_strings[(int)ep];
2285 if (str != edit_point_selector.get_text ()) {
2286 edit_point_selector.set_text (str);
2289 update_all_enter_cursors();
2291 if (!force && !changed) {
2295 const char* action=NULL;
2297 switch (_edit_point) {
2298 case EditAtPlayhead:
2299 action = "edit-at-playhead";
2301 case EditAtSelectedMarker:
2302 action = "edit-at-marker";
2305 action = "edit-at-mouse";
2309 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2311 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2315 bool in_track_canvas;
2317 if (!mouse_frame (foo, in_track_canvas)) {
2318 in_track_canvas = false;
2321 reset_canvas_action_sensitivity (in_track_canvas);
2322 sensitize_the_right_region_actions (false);
2328 Editor::set_state (const XMLNode& node, int version)
2331 PBD::Unwinder<bool> nsi (no_save_instant, true);
2334 Tabbable::set_state (node, version);
2337 if (_session && node.get_property ("playhead", ph_pos)) {
2339 playhead_cursor->set_position (ph_pos);
2341 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2342 playhead_cursor->set_position (0);
2345 playhead_cursor->set_position (0);
2348 node.get_property ("mixer-width", editor_mixer_strip_width);
2350 node.get_property ("zoom-focus", zoom_focus);
2351 zoom_focus_selection_done (zoom_focus);
2354 if (node.get_property ("zoom", z)) {
2355 /* older versions of ardour used floating point samples_per_pixel */
2356 reset_zoom (llrintf (z));
2358 reset_zoom (samples_per_pixel);
2362 if (node.get_property ("visible-track-count", cnt)) {
2363 set_visible_track_count (cnt);
2367 if (!node.get_property ("snap-to", snap_type)) {
2368 snap_type = _snap_type;
2370 set_snap_to (snap_type);
2373 if (node.get_property ("snap-mode", sm)) {
2374 snap_mode_selection_done(sm);
2375 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2376 * snap_mode_selection_done() will only mark an already active item as active
2377 * which does not trigger set_text().
2381 set_snap_mode (_snap_mode);
2384 node.get_property ("internal-snap-to", internal_snap_type);
2385 node.get_property ("internal-snap-mode", internal_snap_mode);
2386 node.get_property ("pre-internal-snap-to", pre_internal_snap_type);
2387 node.get_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2390 if (node.get_property ("mouse-mode", mm_str)) {
2391 MouseMode m = str2mousemode(mm_str);
2392 set_mouse_mode (m, true);
2394 set_mouse_mode (MouseObject, true);
2398 if (node.get_property ("left-frame", lf_pos)) {
2402 reset_x_origin (lf_pos);
2406 if (node.get_property ("y-origin", y_origin)) {
2407 reset_y_origin (y_origin);
2410 if (node.get_property ("join-object-range", yn)) {
2411 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2413 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2414 tact->set_active (!yn);
2415 tact->set_active (yn);
2417 set_mouse_mode(mouse_mode, true);
2421 if (node.get_property ("edit-point", ep)) {
2422 set_edit_point_preference (ep, true);
2424 set_edit_point_preference (_edit_point);
2427 node.get_property ("show-measures", _show_measures);
2429 if (node.get_property ("follow-playhead", yn)) {
2430 set_follow_playhead (yn);
2433 if (node.get_property ("stationary-playhead", yn)) {
2434 set_stationary_playhead (yn);
2437 RegionListSortType sort_type;
2438 if (node.get_property ("region-list-sort-type", sort_type)) {
2439 _regions->reset_sort_type (sort_type, true);
2442 if (node.get_property ("show-editor-mixer", yn)) {
2444 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2447 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2449 /* do it twice to force the change */
2451 tact->set_active (!yn);
2452 tact->set_active (yn);
2455 if (node.get_property ("show-editor-list", yn)) {
2457 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2460 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2462 /* do it twice to force the change */
2464 tact->set_active (!yn);
2465 tact->set_active (yn);
2469 if (node.get_property (X_("editor-list-page"), el_page)) {
2470 _the_notebook.set_current_page (el_page);
2473 if (node.get_property (X_("show-marker-lines"), yn)) {
2474 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2476 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2478 tact->set_active (!yn);
2479 tact->set_active (yn);
2482 XMLNodeList children = node.children ();
2483 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2484 selection->set_state (**i, Stateful::current_state_version);
2485 _regions->set_state (**i);
2486 _locations->set_state (**i);
2489 if (node.get_property ("maximised", yn)) {
2490 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2492 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2493 bool fs = tact && tact->get_active();
2495 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2499 framepos_t nudge_clock_value;
2500 if (node.get_property ("nudge-clock-value", nudge_clock_value)) {
2501 nudge_clock->set (nudge_clock_value);
2503 nudge_clock->set_mode (AudioClock::Timecode);
2504 nudge_clock->set (_session->frame_rate() * 5, true);
2509 * Not all properties may have been in XML, but
2510 * those that are linked to a private variable may need changing
2514 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2516 yn = _show_measures;
2517 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2518 /* do it twice to force the change */
2519 tact->set_active (!yn);
2520 tact->set_active (yn);
2523 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2524 yn = _follow_playhead;
2526 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2527 if (tact->get_active() != yn) {
2528 tact->set_active (yn);
2532 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2533 yn = _stationary_playhead;
2535 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2536 if (tact->get_active() != yn) {
2537 tact->set_active (yn);
2542 return LuaInstance::instance()->set_state(node);
2546 Editor::get_state ()
2548 XMLNode* node = new XMLNode (X_("Editor"));
2550 node->set_property ("id", id().to_s ());
2552 node->add_child_nocopy (Tabbable::get_state());
2554 node->set_property("edit-horizontal-pane-pos", edit_pane.get_divider ());
2555 node->set_property("notebook-shrunk", _notebook_shrunk);
2556 node->set_property("edit-vertical-pane-pos", editor_summary_pane.get_divider());
2558 maybe_add_mixer_strip_width (*node);
2560 node->set_property ("zoom-focus", zoom_focus);
2562 node->set_property ("zoom", samples_per_pixel);
2563 node->set_property ("snap-to", _snap_type);
2564 node->set_property ("snap-mode", _snap_mode);
2565 node->set_property ("internal-snap-to", internal_snap_type);
2566 node->set_property ("internal-snap-mode", internal_snap_mode);
2567 node->set_property ("pre-internal-snap-to", pre_internal_snap_type);
2568 node->set_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2569 node->set_property ("edit-point", _edit_point);
2570 node->set_property ("visible-track-count", _visible_track_count);
2572 node->set_property ("playhead", playhead_cursor->current_frame ());
2573 node->set_property ("left-frame", leftmost_frame);
2574 node->set_property ("y-origin", vertical_adjustment.get_value ());
2576 node->set_property ("show-measures", _show_measures);
2577 node->set_property ("maximised", _maximised);
2578 node->set_property ("follow-playhead", _follow_playhead);
2579 node->set_property ("stationary-playhead", _stationary_playhead);
2580 node->set_property ("region-list-sort-type", _regions->sort_type ());
2581 node->set_property ("mouse-mode", mouse_mode);
2582 node->set_property ("join-object-range", smart_mode_action->get_active ());
2584 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2586 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2587 node->set_property (X_("show-editor-mixer"), tact->get_active());
2590 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2592 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2593 node->set_property (X_("show-editor-list"), tact->get_active());
2596 node->set_property (X_("editor-list-page"), _the_notebook.get_current_page ());
2598 if (button_bindings) {
2599 XMLNode* bb = new XMLNode (X_("Buttons"));
2600 button_bindings->save (*bb);
2601 node->add_child_nocopy (*bb);
2604 node->set_property (X_("show-marker-lines"), _show_marker_lines);
2606 node->add_child_nocopy (selection->get_state ());
2607 node->add_child_nocopy (_regions->get_state ());
2609 node->set_property ("nudge-clock-value", nudge_clock->current_duration());
2611 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2612 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2613 node->add_child_nocopy (_locations->get_state ());
2618 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2619 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2621 * @return pair: TimeAxisView that y is over, layer index.
2623 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2624 * in stacked or expanded region display mode, otherwise 0.
2626 std::pair<TimeAxisView *, double>
2627 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2629 if (!trackview_relative_offset) {
2630 y -= _trackview_group->canvas_origin().y;
2634 return std::make_pair ( (TimeAxisView *) 0, 0);
2637 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2639 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2646 return std::make_pair ( (TimeAxisView *) 0, 0);
2649 /** Snap a position to the grid, if appropriate, taking into account current
2650 * grid settings and also the state of any snap modifier keys that may be pressed.
2651 * @param start Position to snap.
2652 * @param event Event to get current key modifier information from, or 0.
2655 Editor::snap_to_with_modifier (MusicFrame& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2657 if (!_session || !event) {
2661 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2662 if (_snap_mode == SnapOff) {
2663 snap_to_internal (start, direction, for_mark);
2665 start.set (start.frame, 0);
2668 if (_snap_mode != SnapOff) {
2669 snap_to_internal (start, direction, for_mark);
2670 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2671 /* SnapOff, but we pressed the snap_delta modifier */
2672 snap_to_internal (start, direction, for_mark);
2674 start.set (start.frame, 0);
2680 Editor::snap_to (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap)
2682 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2683 start.set (start.frame, 0);
2687 snap_to_internal (start, direction, for_mark, ensure_snap);
2691 Editor::timecode_snap_to_internal (MusicFrame& pos, RoundMode direction, bool /*for_mark*/)
2693 framepos_t start = pos.frame;
2694 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2695 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2697 switch (_snap_type) {
2698 case SnapToTimecodeFrame:
2699 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2700 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2701 /* start is already on a whole timecode frame, do nothing */
2702 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2703 start = (framepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2705 start = (framepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2709 case SnapToTimecodeSeconds:
2710 if (_session->config.get_timecode_offset_negative()) {
2711 start += _session->config.get_timecode_offset ();
2713 start -= _session->config.get_timecode_offset ();
2715 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2716 (start % one_timecode_second == 0)) {
2717 /* start is already on a whole second, do nothing */
2718 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2719 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2721 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2724 if (_session->config.get_timecode_offset_negative()) {
2725 start -= _session->config.get_timecode_offset ();
2727 start += _session->config.get_timecode_offset ();
2731 case SnapToTimecodeMinutes:
2732 if (_session->config.get_timecode_offset_negative()) {
2733 start += _session->config.get_timecode_offset ();
2735 start -= _session->config.get_timecode_offset ();
2737 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2738 (start % one_timecode_minute == 0)) {
2739 /* start is already on a whole minute, do nothing */
2740 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2741 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2743 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2745 if (_session->config.get_timecode_offset_negative()) {
2746 start -= _session->config.get_timecode_offset ();
2748 start += _session->config.get_timecode_offset ();
2752 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2753 abort(); /*NOTREACHED*/
2760 Editor::snap_to_internal (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap)
2762 const framepos_t one_second = _session->frame_rate();
2763 const framepos_t one_minute = _session->frame_rate() * 60;
2764 framepos_t presnap = start.frame;
2768 switch (_snap_type) {
2769 case SnapToTimecodeFrame:
2770 case SnapToTimecodeSeconds:
2771 case SnapToTimecodeMinutes:
2772 return timecode_snap_to_internal (start, direction, for_mark);
2775 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2776 start.frame % (one_second/75) == 0) {
2777 /* start is already on a whole CD frame, do nothing */
2778 } else if (((direction == 0) && (start.frame % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2779 start.frame = (framepos_t) ceil ((double) start.frame / (one_second / 75)) * (one_second / 75);
2781 start.frame = (framepos_t) floor ((double) start.frame / (one_second / 75)) * (one_second / 75);
2784 start.set (start.frame, 0);
2789 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2790 start.frame % one_second == 0) {
2791 /* start is already on a whole second, do nothing */
2792 } else if (((direction == 0) && (start.frame % one_second > one_second / 2)) || (direction > 0)) {
2793 start.frame = (framepos_t) ceil ((double) start.frame / one_second) * one_second;
2795 start.frame = (framepos_t) floor ((double) start.frame / one_second) * one_second;
2798 start.set (start.frame, 0);
2803 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2804 start.frame % one_minute == 0) {
2805 /* start is already on a whole minute, do nothing */
2806 } else if (((direction == 0) && (start.frame % one_minute > one_minute / 2)) || (direction > 0)) {
2807 start.frame = (framepos_t) ceil ((double) start.frame / one_minute) * one_minute;
2809 start.frame = (framepos_t) floor ((double) start.frame / one_minute) * one_minute;
2812 start.set (start.frame, 0);
2817 start = _session->tempo_map().round_to_bar (start.frame, direction);
2821 start = _session->tempo_map().round_to_beat (start.frame, direction);
2824 case SnapToBeatDiv128:
2825 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 128, direction);
2827 case SnapToBeatDiv64:
2828 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 64, direction);
2830 case SnapToBeatDiv32:
2831 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 32, direction);
2833 case SnapToBeatDiv28:
2834 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 28, direction);
2836 case SnapToBeatDiv24:
2837 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 24, direction);
2839 case SnapToBeatDiv20:
2840 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 20, direction);
2842 case SnapToBeatDiv16:
2843 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 16, direction);
2845 case SnapToBeatDiv14:
2846 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 14, direction);
2848 case SnapToBeatDiv12:
2849 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 12, direction);
2851 case SnapToBeatDiv10:
2852 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 10, direction);
2854 case SnapToBeatDiv8:
2855 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 8, direction);
2857 case SnapToBeatDiv7:
2858 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 7, direction);
2860 case SnapToBeatDiv6:
2861 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 6, direction);
2863 case SnapToBeatDiv5:
2864 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 5, direction);
2866 case SnapToBeatDiv4:
2867 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 4, direction);
2869 case SnapToBeatDiv3:
2870 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 3, direction);
2872 case SnapToBeatDiv2:
2873 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 2, direction);
2881 _session->locations()->marks_either_side (start.frame, before, after);
2883 if (before == max_framepos && after == max_framepos) {
2884 /* No marks to snap to, so just don't snap */
2886 } else if (before == max_framepos) {
2887 start.frame = after;
2888 } else if (after == max_framepos) {
2889 start.frame = before;
2890 } else if (before != max_framepos && after != max_framepos) {
2891 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2892 start.frame = after;
2893 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2894 start.frame = before;
2895 else if (direction == 0 ) {
2896 if ((start.frame - before) < (after - start.frame)) {
2897 start.frame = before;
2899 start.frame = after;
2904 start.set (start.frame, 0);
2908 case SnapToRegionStart:
2909 case SnapToRegionEnd:
2910 case SnapToRegionSync:
2911 case SnapToRegionBoundary:
2912 if (!region_boundary_cache.empty()) {
2914 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2915 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2917 if (direction > 0) {
2918 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame);
2920 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame);
2923 if (next != region_boundary_cache.begin ()) {
2928 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2929 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2931 if (start.frame > (p + n) / 2) {
2938 start.set (start.frame, 0);
2943 switch (_snap_mode) {
2953 if (presnap > start.frame) {
2954 if (presnap > (start.frame + pixel_to_sample(snap_threshold))) {
2955 start.set (presnap, 0);
2958 } else if (presnap < start.frame) {
2959 if (presnap < (start.frame - pixel_to_sample(snap_threshold))) {
2960 start.set (presnap, 0);
2965 /* handled at entry */
2972 Editor::setup_toolbar ()
2974 HBox* mode_box = manage(new HBox);
2975 mode_box->set_border_width (2);
2976 mode_box->set_spacing(2);
2978 HBox* mouse_mode_box = manage (new HBox);
2979 HBox* mouse_mode_hbox = manage (new HBox);
2980 VBox* mouse_mode_vbox = manage (new VBox);
2981 Alignment* mouse_mode_align = manage (new Alignment);
2983 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2984 mouse_mode_size_group->add_widget (smart_mode_button);
2985 mouse_mode_size_group->add_widget (mouse_move_button);
2986 mouse_mode_size_group->add_widget (mouse_cut_button);
2987 mouse_mode_size_group->add_widget (mouse_select_button);
2988 mouse_mode_size_group->add_widget (mouse_timefx_button);
2989 mouse_mode_size_group->add_widget (mouse_audition_button);
2990 mouse_mode_size_group->add_widget (mouse_draw_button);
2991 mouse_mode_size_group->add_widget (mouse_content_button);
2993 if (!Profile->get_mixbus()) {
2994 mouse_mode_size_group->add_widget (zoom_in_button);
2995 mouse_mode_size_group->add_widget (zoom_out_button);
2996 mouse_mode_size_group->add_widget (zoom_out_full_button);
2997 mouse_mode_size_group->add_widget (zoom_focus_selector);
2998 mouse_mode_size_group->add_widget (tav_shrink_button);
2999 mouse_mode_size_group->add_widget (tav_expand_button);
3001 mouse_mode_size_group->add_widget (zoom_preset_selector);
3002 mouse_mode_size_group->add_widget (visible_tracks_selector);
3005 mouse_mode_size_group->add_widget (snap_type_selector);
3006 mouse_mode_size_group->add_widget (snap_mode_selector);
3008 mouse_mode_size_group->add_widget (edit_point_selector);
3009 mouse_mode_size_group->add_widget (edit_mode_selector);
3011 mouse_mode_size_group->add_widget (*nudge_clock);
3012 mouse_mode_size_group->add_widget (nudge_forward_button);
3013 mouse_mode_size_group->add_widget (nudge_backward_button);
3015 mouse_mode_hbox->set_spacing (2);
3017 if (!ARDOUR::Profile->get_trx()) {
3018 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3021 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3022 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3024 if (!ARDOUR::Profile->get_mixbus()) {
3025 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3028 if (!ARDOUR::Profile->get_trx()) {
3029 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3030 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3031 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3032 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3035 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3037 mouse_mode_align->add (*mouse_mode_vbox);
3038 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3040 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3042 edit_mode_selector.set_name ("mouse mode button");
3044 if (!ARDOUR::Profile->get_trx()) {
3045 mode_box->pack_start (edit_mode_selector, false, false);
3048 mode_box->pack_start (*mouse_mode_box, false, false);
3052 _zoom_box.set_spacing (2);
3053 _zoom_box.set_border_width (2);
3057 zoom_preset_selector.set_name ("zoom button");
3058 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
3060 zoom_in_button.set_name ("zoom button");
3061 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3062 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3063 zoom_in_button.set_related_action (act);
3065 zoom_out_button.set_name ("zoom button");
3066 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3067 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3068 zoom_out_button.set_related_action (act);
3070 zoom_out_full_button.set_name ("zoom button");
3071 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3072 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3073 zoom_out_full_button.set_related_action (act);
3075 zoom_focus_selector.set_name ("zoom button");
3077 if (ARDOUR::Profile->get_mixbus()) {
3078 _zoom_box.pack_start (zoom_preset_selector, false, false);
3079 } else if (ARDOUR::Profile->get_trx()) {
3080 mode_box->pack_start (zoom_out_button, false, false);
3081 mode_box->pack_start (zoom_in_button, false, false);
3083 _zoom_box.pack_start (zoom_out_button, false, false);
3084 _zoom_box.pack_start (zoom_in_button, false, false);
3085 _zoom_box.pack_start (zoom_out_full_button, false, false);
3086 _zoom_box.pack_start (zoom_focus_selector, false, false);
3089 /* Track zoom buttons */
3090 _track_box.set_spacing (2);
3091 _track_box.set_border_width (2);
3093 visible_tracks_selector.set_name ("zoom button");
3094 if (Profile->get_mixbus()) {
3095 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3097 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3100 tav_expand_button.set_name ("zoom button");
3101 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3102 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3103 tav_expand_button.set_related_action (act);
3105 tav_shrink_button.set_name ("zoom button");
3106 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3107 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3108 tav_shrink_button.set_related_action (act);
3110 if (ARDOUR::Profile->get_mixbus()) {
3111 _track_box.pack_start (visible_tracks_selector);
3112 } else if (ARDOUR::Profile->get_trx()) {
3113 _track_box.pack_start (tav_shrink_button);
3114 _track_box.pack_start (tav_expand_button);
3116 _track_box.pack_start (visible_tracks_selector);
3117 _track_box.pack_start (tav_shrink_button);
3118 _track_box.pack_start (tav_expand_button);
3121 snap_box.set_spacing (2);
3122 snap_box.set_border_width (2);
3124 snap_type_selector.set_name ("mouse mode button");
3126 snap_mode_selector.set_name ("mouse mode button");
3128 edit_point_selector.set_name ("mouse mode button");
3130 snap_box.pack_start (snap_mode_selector, false, false);
3131 snap_box.pack_start (snap_type_selector, false, false);
3134 HBox *ep_box = manage (new HBox);
3135 ep_box->set_spacing (2);
3136 ep_box->set_border_width (2);
3138 ep_box->pack_start (edit_point_selector, false, false);
3142 HBox *nudge_box = manage (new HBox);
3143 nudge_box->set_spacing (2);
3144 nudge_box->set_border_width (2);
3146 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3147 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3149 nudge_box->pack_start (nudge_backward_button, false, false);
3150 nudge_box->pack_start (nudge_forward_button, false, false);
3151 nudge_box->pack_start (*nudge_clock, false, false);
3154 /* Pack everything in... */
3156 toolbar_hbox.set_spacing (2);
3157 toolbar_hbox.set_border_width (2);
3159 toolbar_hbox.pack_start (*mode_box, false, false);
3161 if (!ARDOUR::Profile->get_trx()) {
3163 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3165 toolbar_hbox.pack_start (_zoom_box, false, false);
3167 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3169 toolbar_hbox.pack_start (_track_box, false, false);
3171 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3173 toolbar_hbox.pack_start (snap_box, false, false);
3175 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3177 toolbar_hbox.pack_start (*ep_box, false, false);
3179 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3181 toolbar_hbox.pack_start (*nudge_box, false, false);
3184 toolbar_hbox.show_all ();
3188 Editor::build_edit_point_menu ()
3190 using namespace Menu_Helpers;
3192 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3193 if(!Profile->get_mixbus())
3194 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3195 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3197 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3201 Editor::build_edit_mode_menu ()
3203 using namespace Menu_Helpers;
3205 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3206 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3207 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3208 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3210 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3214 Editor::build_snap_mode_menu ()
3216 using namespace Menu_Helpers;
3218 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3219 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3220 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3222 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3226 Editor::build_snap_type_menu ()
3228 using namespace Menu_Helpers;
3230 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3231 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3232 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3233 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3234 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3235 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3236 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3237 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3238 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3239 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3240 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3241 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3242 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3243 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3244 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3245 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3246 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3247 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3248 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3249 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3250 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3251 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3252 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3253 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3254 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3255 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3256 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3257 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3258 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3259 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3261 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3266 Editor::setup_tooltips ()
3268 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3269 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3270 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3271 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3272 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3273 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3274 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3275 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3276 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3277 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3278 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3279 set_tooltip (zoom_in_button, _("Zoom In"));
3280 set_tooltip (zoom_out_button, _("Zoom Out"));
3281 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3282 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3283 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3284 set_tooltip (tav_expand_button, _("Expand Tracks"));
3285 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3286 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3287 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3288 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3289 set_tooltip (edit_point_selector, _("Edit Point"));
3290 set_tooltip (edit_mode_selector, _("Edit Mode"));
3291 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3295 Editor::convert_drop_to_paths (
3296 vector<string>& paths,
3297 const RefPtr<Gdk::DragContext>& /*context*/,
3300 const SelectionData& data,
3304 if (_session == 0) {
3308 vector<string> uris = data.get_uris();
3312 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3313 are actually URI lists. So do it by hand.
3316 if (data.get_target() != "text/plain") {
3320 /* Parse the "uri-list" format that Nautilus provides,
3321 where each pathname is delimited by \r\n.
3323 THERE MAY BE NO NULL TERMINATING CHAR!!!
3326 string txt = data.get_text();
3330 p = (char *) malloc (txt.length() + 1);
3331 txt.copy (p, txt.length(), 0);
3332 p[txt.length()] = '\0';
3338 while (g_ascii_isspace (*p))
3342 while (*q && (*q != '\n') && (*q != '\r')) {
3349 while (q > p && g_ascii_isspace (*q))
3354 uris.push_back (string (p, q - p + 1));
3358 p = strchr (p, '\n');
3370 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3371 if ((*i).substr (0,7) == "file://") {
3372 paths.push_back (Glib::filename_from_uri (*i));
3380 Editor::new_tempo_section ()
3385 Editor::map_transport_state ()
3387 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3389 if (_session && _session->transport_stopped()) {
3390 have_pending_keyboard_selection = false;
3393 update_loop_range_view ();
3397 Editor::transport_looped ()
3399 /* reset Playhead position interpolation.
3400 * see Editor::super_rapid_screen_update
3402 _last_update_time = 0;
3408 Editor::begin_selection_op_history ()
3410 selection_op_cmd_depth = 0;
3411 selection_op_history_it = 0;
3413 while(!selection_op_history.empty()) {
3414 delete selection_op_history.front();
3415 selection_op_history.pop_front();
3418 selection_undo_action->set_sensitive (false);
3419 selection_redo_action->set_sensitive (false);
3420 selection_op_history.push_front (&_selection_memento->get_state ());
3424 Editor::begin_reversible_selection_op (string name)
3427 //cerr << name << endl;
3428 /* begin/commit pairs can be nested */
3429 selection_op_cmd_depth++;
3434 Editor::commit_reversible_selection_op ()
3437 if (selection_op_cmd_depth == 1) {
3439 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3441 The user has undone some selection ops and then made a new one,
3442 making anything earlier in the list invalid.
3445 list<XMLNode *>::iterator it = selection_op_history.begin();
3446 list<XMLNode *>::iterator e_it = it;
3447 advance (e_it, selection_op_history_it);
3449 for ( ; it != e_it; ++it) {
3452 selection_op_history.erase (selection_op_history.begin(), e_it);
3455 selection_op_history.push_front (&_selection_memento->get_state ());
3456 selection_op_history_it = 0;
3458 selection_undo_action->set_sensitive (true);
3459 selection_redo_action->set_sensitive (false);
3462 if (selection_op_cmd_depth > 0) {
3463 selection_op_cmd_depth--;
3469 Editor::undo_selection_op ()
3472 selection_op_history_it++;
3474 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3475 if (n == selection_op_history_it) {
3476 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3477 selection_redo_action->set_sensitive (true);
3481 /* is there an earlier entry? */
3482 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3483 selection_undo_action->set_sensitive (false);
3489 Editor::redo_selection_op ()
3492 if (selection_op_history_it > 0) {
3493 selection_op_history_it--;
3496 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3497 if (n == selection_op_history_it) {
3498 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3499 selection_undo_action->set_sensitive (true);
3504 if (selection_op_history_it == 0) {
3505 selection_redo_action->set_sensitive (false);
3511 Editor::begin_reversible_command (string name)
3514 before.push_back (&_selection_memento->get_state ());
3515 _session->begin_reversible_command (name);
3520 Editor::begin_reversible_command (GQuark q)
3523 before.push_back (&_selection_memento->get_state ());
3524 _session->begin_reversible_command (q);
3529 Editor::abort_reversible_command ()
3532 while(!before.empty()) {
3533 delete before.front();
3536 _session->abort_reversible_command ();
3541 Editor::commit_reversible_command ()
3544 if (before.size() == 1) {
3545 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3546 redo_action->set_sensitive(false);
3547 undo_action->set_sensitive(true);
3548 begin_selection_op_history ();
3551 if (before.empty()) {
3552 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3557 _session->commit_reversible_command ();
3562 Editor::history_changed ()
3566 if (undo_action && _session) {
3567 if (_session->undo_depth() == 0) {
3568 label = S_("Command|Undo");
3570 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3572 undo_action->property_label() = label;
3575 if (redo_action && _session) {
3576 if (_session->redo_depth() == 0) {
3578 redo_action->set_sensitive (false);
3580 label = string_compose(_("Redo (%1)"), _session->next_redo());
3581 redo_action->set_sensitive (true);
3583 redo_action->property_label() = label;
3588 Editor::duplicate_range (bool with_dialog)
3592 RegionSelection rs = get_regions_from_selection_and_entered ();
3594 if ( selection->time.length() == 0 && rs.empty()) {
3600 ArdourDialog win (_("Duplicate"));
3601 Label label (_("Number of duplications:"));
3602 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3603 SpinButton spinner (adjustment, 0.0, 1);
3606 win.get_vbox()->set_spacing (12);
3607 win.get_vbox()->pack_start (hbox);
3608 hbox.set_border_width (6);
3609 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3611 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3612 place, visually. so do this by hand.
3615 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3616 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3617 spinner.grab_focus();
3623 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3624 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3625 win.set_default_response (RESPONSE_ACCEPT);
3627 spinner.grab_focus ();
3629 switch (win.run ()) {
3630 case RESPONSE_ACCEPT:
3636 times = adjustment.get_value();
3639 if ((current_mouse_mode() == Editing::MouseRange)) {
3640 if (selection->time.length()) {
3641 duplicate_selection (times);
3643 } else if (get_smart_mode()) {
3644 if (selection->time.length()) {
3645 duplicate_selection (times);
3647 duplicate_some_regions (rs, times);
3649 duplicate_some_regions (rs, times);
3654 Editor::set_edit_mode (EditMode m)
3656 Config->set_edit_mode (m);
3660 Editor::cycle_edit_mode ()
3662 switch (Config->get_edit_mode()) {
3664 Config->set_edit_mode (Ripple);
3668 Config->set_edit_mode (Lock);
3671 Config->set_edit_mode (Slide);
3677 Editor::edit_mode_selection_done ( EditMode m )
3679 Config->set_edit_mode ( m );
3683 Editor::snap_type_selection_done (SnapType snaptype)
3685 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3687 ract->set_active ();
3692 Editor::snap_mode_selection_done (SnapMode mode)
3694 RefPtr<RadioAction> ract = snap_mode_action (mode);
3697 ract->set_active (true);
3702 Editor::cycle_edit_point (bool with_marker)
3704 if(Profile->get_mixbus())
3705 with_marker = false;
3707 switch (_edit_point) {
3709 set_edit_point_preference (EditAtPlayhead);
3711 case EditAtPlayhead:
3713 set_edit_point_preference (EditAtSelectedMarker);
3715 set_edit_point_preference (EditAtMouse);
3718 case EditAtSelectedMarker:
3719 set_edit_point_preference (EditAtMouse);
3725 Editor::edit_point_selection_done (EditPoint ep)
3727 set_edit_point_preference ( ep );
3731 Editor::build_zoom_focus_menu ()
3733 using namespace Menu_Helpers;
3735 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3736 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3737 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3738 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3739 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3740 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3742 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3746 Editor::zoom_focus_selection_done ( ZoomFocus f )
3748 RefPtr<RadioAction> ract = zoom_focus_action (f);
3750 ract->set_active ();
3755 Editor::build_track_count_menu ()
3757 using namespace Menu_Helpers;
3759 if (!Profile->get_mixbus()) {
3760 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3761 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3762 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3763 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3764 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3765 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3766 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3767 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3768 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3769 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3770 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3771 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3772 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3774 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3775 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3776 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3777 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3778 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3779 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3780 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3781 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3782 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3783 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3785 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3786 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3787 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3788 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3789 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3790 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3791 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3792 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3793 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3794 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3795 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3800 Editor::set_zoom_preset (int64_t ms)
3803 temporal_zoom_session();
3807 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3808 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3812 Editor::set_visible_track_count (int32_t n)
3814 _visible_track_count = n;
3816 /* if the canvas hasn't really been allocated any size yet, just
3817 record the desired number of visible tracks and return. when canvas
3818 allocation happens, we will get called again and then we can do the
3822 if (_visible_canvas_height <= 1) {
3828 DisplaySuspender ds;
3830 if (_visible_track_count > 0) {
3831 h = trackviews_height() / _visible_track_count;
3832 std::ostringstream s;
3833 s << _visible_track_count;
3835 } else if (_visible_track_count == 0) {
3837 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3838 if ((*i)->marked_for_display()) {
3842 h = trackviews_height() / n;
3845 /* negative value means that the visible track count has
3846 been overridden by explicit track height changes.
3848 visible_tracks_selector.set_text (X_("*"));
3852 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3853 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3856 if (str != visible_tracks_selector.get_text()) {
3857 visible_tracks_selector.set_text (str);
3862 Editor::override_visible_track_count ()
3864 _visible_track_count = -1;
3865 visible_tracks_selector.set_text ( _("*") );
3869 Editor::edit_controls_button_release (GdkEventButton* ev)
3871 if (Keyboard::is_context_menu_event (ev)) {
3872 ARDOUR_UI::instance()->add_route ();
3873 } else if (ev->button == 1) {
3874 selection->clear_tracks ();
3881 Editor::mouse_select_button_release (GdkEventButton* ev)
3883 /* this handles just right-clicks */
3885 if (ev->button != 3) {
3893 Editor::set_zoom_focus (ZoomFocus f)
3895 string str = zoom_focus_strings[(int)f];
3897 if (str != zoom_focus_selector.get_text()) {
3898 zoom_focus_selector.set_text (str);
3901 if (zoom_focus != f) {
3908 Editor::cycle_zoom_focus ()
3910 switch (zoom_focus) {
3912 set_zoom_focus (ZoomFocusRight);
3914 case ZoomFocusRight:
3915 set_zoom_focus (ZoomFocusCenter);
3917 case ZoomFocusCenter:
3918 set_zoom_focus (ZoomFocusPlayhead);
3920 case ZoomFocusPlayhead:
3921 set_zoom_focus (ZoomFocusMouse);
3923 case ZoomFocusMouse:
3924 set_zoom_focus (ZoomFocusEdit);
3927 set_zoom_focus (ZoomFocusLeft);
3933 Editor::set_show_measures (bool yn)
3935 if (_show_measures != yn) {
3938 if ((_show_measures = yn) == true) {
3940 tempo_lines->show();
3943 std::vector<TempoMap::BBTPoint> grid;
3944 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3945 draw_measures (grid);
3953 Editor::toggle_follow_playhead ()
3955 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3957 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3958 set_follow_playhead (tact->get_active());
3962 /** @param yn true to follow playhead, otherwise false.
3963 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3966 Editor::set_follow_playhead (bool yn, bool catch_up)
3968 if (_follow_playhead != yn) {
3969 if ((_follow_playhead = yn) == true && catch_up) {
3971 reset_x_origin_to_follow_playhead ();
3978 Editor::toggle_stationary_playhead ()
3980 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3982 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3983 set_stationary_playhead (tact->get_active());
3988 Editor::set_stationary_playhead (bool yn)
3990 if (_stationary_playhead != yn) {
3991 if ((_stationary_playhead = yn) == true) {
3993 // FIXME need a 3.0 equivalent of this 2.X call
3994 // update_current_screen ();
4001 Editor::playlist_selector () const
4003 return *_playlist_selector;
4007 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4009 if (paste_count == 0) {
4010 /* don't bother calculating an offset that will be zero anyway */
4014 /* calculate basic unsnapped multi-paste offset */
4015 framecnt_t offset = paste_count * duration;
4017 /* snap offset so pos + offset is aligned to the grid */
4018 MusicFrame offset_pos (pos + offset, 0);
4019 snap_to(offset_pos, RoundUpMaybe);
4020 offset = offset_pos.frame - pos;
4026 Editor::get_grid_beat_divisions(framepos_t position)
4028 switch (_snap_type) {
4029 case SnapToBeatDiv128: return 128;
4030 case SnapToBeatDiv64: return 64;
4031 case SnapToBeatDiv32: return 32;
4032 case SnapToBeatDiv28: return 28;
4033 case SnapToBeatDiv24: return 24;
4034 case SnapToBeatDiv20: return 20;
4035 case SnapToBeatDiv16: return 16;
4036 case SnapToBeatDiv14: return 14;
4037 case SnapToBeatDiv12: return 12;
4038 case SnapToBeatDiv10: return 10;
4039 case SnapToBeatDiv8: return 8;
4040 case SnapToBeatDiv7: return 7;
4041 case SnapToBeatDiv6: return 6;
4042 case SnapToBeatDiv5: return 5;
4043 case SnapToBeatDiv4: return 4;
4044 case SnapToBeatDiv3: return 3;
4045 case SnapToBeatDiv2: return 2;
4051 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4052 if the grid is non-musical, returns 0.
4053 if the grid is snapped to bars, returns -1.
4054 @param event_state the current keyboard modifier mask.
4057 Editor::get_grid_music_divisions (uint32_t event_state)
4059 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4063 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4067 switch (_snap_type) {
4068 case SnapToBeatDiv128: return 128;
4069 case SnapToBeatDiv64: return 64;
4070 case SnapToBeatDiv32: return 32;
4071 case SnapToBeatDiv28: return 28;
4072 case SnapToBeatDiv24: return 24;
4073 case SnapToBeatDiv20: return 20;
4074 case SnapToBeatDiv16: return 16;
4075 case SnapToBeatDiv14: return 14;
4076 case SnapToBeatDiv12: return 12;
4077 case SnapToBeatDiv10: return 10;
4078 case SnapToBeatDiv8: return 8;
4079 case SnapToBeatDiv7: return 7;
4080 case SnapToBeatDiv6: return 6;
4081 case SnapToBeatDiv5: return 5;
4082 case SnapToBeatDiv4: return 4;
4083 case SnapToBeatDiv3: return 3;
4084 case SnapToBeatDiv2: return 2;
4085 case SnapToBeat: return 1;
4086 case SnapToBar : return -1;
4093 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4097 const unsigned divisions = get_grid_beat_divisions(position);
4099 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4102 switch (_snap_type) {
4104 return Evoral::Beats(4.0 / _session->tempo_map().meter_at_frame (position).note_divisor());
4107 const Meter& m = _session->tempo_map().meter_at_frame (position);
4108 return Evoral::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4116 return Evoral::Beats();
4120 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4124 ret = nudge_clock->current_duration (pos);
4125 next = ret + 1; /* XXXX fix me */
4131 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4133 ArdourDialog dialog (_("Playlist Deletion"));
4134 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4135 "If it is kept, its audio files will not be cleaned.\n"
4136 "If it is deleted, audio files used by it alone will be cleaned."),
4139 dialog.set_position (WIN_POS_CENTER);
4140 dialog.get_vbox()->pack_start (label);
4144 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4145 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4146 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4147 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4148 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4150 // by default gtk uses the left most button
4151 keep->grab_focus ();
4153 switch (dialog.run ()) {
4155 /* keep this and all remaining ones */
4160 /* delete this and all others */
4164 case RESPONSE_ACCEPT:
4165 /* delete the playlist */
4169 case RESPONSE_REJECT:
4170 /* keep the playlist */
4182 Editor::audio_region_selection_covers (framepos_t where)
4184 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4185 if ((*a)->region()->covers (where)) {
4194 Editor::prepare_for_cleanup ()
4196 cut_buffer->clear_regions ();
4197 cut_buffer->clear_playlists ();
4199 selection->clear_regions ();
4200 selection->clear_playlists ();
4202 _regions->suspend_redisplay ();
4206 Editor::finish_cleanup ()
4208 _regions->resume_redisplay ();
4212 Editor::transport_loop_location()
4215 return _session->locations()->auto_loop_location();
4222 Editor::transport_punch_location()
4225 return _session->locations()->auto_punch_location();
4232 Editor::control_layout_scroll (GdkEventScroll* ev)
4234 /* Just forward to the normal canvas scroll method. The coordinate
4235 systems are different but since the canvas is always larger than the
4236 track headers, and aligned with the trackview area, this will work.
4238 In the not too distant future this layout is going away anyway and
4239 headers will be on the canvas.
4241 return canvas_scroll_event (ev, false);
4245 Editor::session_state_saved (string)
4248 _snapshots->redisplay ();
4252 Editor::maximise_editing_space ()
4258 Gtk::Window* toplevel = current_toplevel();
4261 toplevel->fullscreen ();
4267 Editor::restore_editing_space ()
4273 Gtk::Window* toplevel = current_toplevel();
4276 toplevel->unfullscreen();
4282 * Make new playlists for a given track and also any others that belong
4283 * to the same active route group with the `select' property.
4288 Editor::new_playlists (TimeAxisView* v)
4290 begin_reversible_command (_("new playlists"));
4291 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4292 _session->playlists->get (playlists);
4293 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4294 commit_reversible_command ();
4298 * Use a copy of the current playlist for a given track and also any others that belong
4299 * to the same active route group with the `select' property.
4304 Editor::copy_playlists (TimeAxisView* v)
4306 begin_reversible_command (_("copy playlists"));
4307 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4308 _session->playlists->get (playlists);
4309 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4310 commit_reversible_command ();
4313 /** Clear the current playlist for a given track and also any others that belong
4314 * to the same active route group with the `select' property.
4319 Editor::clear_playlists (TimeAxisView* v)
4321 begin_reversible_command (_("clear playlists"));
4322 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4323 _session->playlists->get (playlists);
4324 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4325 commit_reversible_command ();
4329 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4331 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4335 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4337 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4341 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4343 atv.clear_playlist ();
4347 Editor::get_y_origin () const
4349 return vertical_adjustment.get_value ();
4352 /** Queue up a change to the viewport x origin.
4353 * @param frame New x origin.
4356 Editor::reset_x_origin (framepos_t frame)
4358 pending_visual_change.add (VisualChange::TimeOrigin);
4359 pending_visual_change.time_origin = frame;
4360 ensure_visual_change_idle_handler ();
4364 Editor::reset_y_origin (double y)
4366 pending_visual_change.add (VisualChange::YOrigin);
4367 pending_visual_change.y_origin = y;
4368 ensure_visual_change_idle_handler ();
4372 Editor::reset_zoom (framecnt_t spp)
4374 if (spp == samples_per_pixel) {
4378 pending_visual_change.add (VisualChange::ZoomLevel);
4379 pending_visual_change.samples_per_pixel = spp;
4380 ensure_visual_change_idle_handler ();
4384 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4386 reset_x_origin (frame);
4389 if (!no_save_visual) {
4390 undo_visual_stack.push_back (current_visual_state(false));
4394 Editor::VisualState::VisualState (bool with_tracks)
4395 : gui_state (with_tracks ? new GUIObjectState : 0)
4399 Editor::VisualState::~VisualState ()
4404 Editor::VisualState*
4405 Editor::current_visual_state (bool with_tracks)
4407 VisualState* vs = new VisualState (with_tracks);
4408 vs->y_position = vertical_adjustment.get_value();
4409 vs->samples_per_pixel = samples_per_pixel;
4410 vs->leftmost_frame = leftmost_frame;
4411 vs->zoom_focus = zoom_focus;
4414 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4421 Editor::undo_visual_state ()
4423 if (undo_visual_stack.empty()) {
4427 VisualState* vs = undo_visual_stack.back();
4428 undo_visual_stack.pop_back();
4431 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4434 use_visual_state (*vs);
4439 Editor::redo_visual_state ()
4441 if (redo_visual_stack.empty()) {
4445 VisualState* vs = redo_visual_stack.back();
4446 redo_visual_stack.pop_back();
4448 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4449 // why do we check here?
4450 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4453 use_visual_state (*vs);
4458 Editor::swap_visual_state ()
4460 if (undo_visual_stack.empty()) {
4461 redo_visual_state ();
4463 undo_visual_state ();
4468 Editor::use_visual_state (VisualState& vs)
4470 PBD::Unwinder<bool> nsv (no_save_visual, true);
4471 DisplaySuspender ds;
4473 vertical_adjustment.set_value (vs.y_position);
4475 set_zoom_focus (vs.zoom_focus);
4476 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4479 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4481 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4482 (*i)->clear_property_cache();
4483 (*i)->reset_visual_state ();
4487 _routes->update_visibility ();
4490 /** This is the core function that controls the zoom level of the canvas. It is called
4491 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4492 * @param spp new number of samples per pixel
4495 Editor::set_samples_per_pixel (framecnt_t spp)
4501 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4502 const framecnt_t lots_of_pixels = 4000;
4504 /* if the zoom level is greater than what you'd get trying to display 3
4505 * days of audio on a really big screen, then it's too big.
4508 if (spp * lots_of_pixels > three_days) {
4512 samples_per_pixel = spp;
4516 Editor::on_samples_per_pixel_changed ()
4519 tempo_lines->tempo_map_changed(_session->tempo_map().music_origin());
4522 bool const showing_time_selection = selection->time.length() > 0;
4524 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4525 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4526 (*i)->reshow_selection (selection->time);
4530 ZoomChanged (); /* EMIT_SIGNAL */
4532 ArdourCanvas::GtkCanvasViewport* c;
4534 c = get_track_canvas();
4536 c->canvas()->zoomed ();
4539 if (playhead_cursor) {
4540 playhead_cursor->set_position (playhead_cursor->current_frame ());
4543 refresh_location_display();
4544 _summary->set_overlays_dirty ();
4546 update_marker_labels ();
4552 Editor::playhead_cursor_sample () const
4554 return playhead_cursor->current_frame();
4558 Editor::queue_visual_videotimeline_update ()
4561 * pending_visual_change.add (VisualChange::VideoTimeline);
4562 * or maybe even more specific: which videotimeline-image
4563 * currently it calls update_video_timeline() to update
4564 * _all outdated_ images on the video-timeline.
4565 * see 'exposeimg()' in video_image_frame.cc
4567 ensure_visual_change_idle_handler ();
4571 Editor::ensure_visual_change_idle_handler ()
4573 if (pending_visual_change.idle_handler_id < 0) {
4574 // see comment in add_to_idle_resize above.
4575 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4576 pending_visual_change.being_handled = false;
4581 Editor::_idle_visual_changer (void* arg)
4583 return static_cast<Editor*>(arg)->idle_visual_changer ();
4587 Editor::pre_render ()
4589 visual_change_queued = false;
4591 if (pending_visual_change.pending != 0) {
4592 ensure_visual_change_idle_handler();
4597 Editor::idle_visual_changer ()
4599 if (pending_visual_change.pending == 0) {
4603 /* set_horizontal_position() below (and maybe other calls) call
4604 gtk_main_iteration(), so it's possible that a signal will be handled
4605 half-way through this method. If this signal wants an
4606 idle_visual_changer we must schedule another one after this one, so
4607 mark the idle_handler_id as -1 here to allow that. Also make a note
4608 that we are doing the visual change, so that changes in response to
4609 super-rapid-screen-update can be dropped if we are still processing
4613 pending_visual_change.idle_handler_id = -1;
4615 if (visual_change_queued) {
4619 pending_visual_change.being_handled = true;
4621 VisualChange vc = pending_visual_change;
4623 pending_visual_change.pending = (VisualChange::Type) 0;
4625 visual_changer (vc);
4627 pending_visual_change.being_handled = false;
4629 visual_change_queued = true;
4631 return 0; /* this is always a one-shot call */
4635 Editor::visual_changer (const VisualChange& vc)
4638 * Changed first so the correct horizontal canvas position is calculated in
4639 * Editor::set_horizontal_position
4641 if (vc.pending & VisualChange::ZoomLevel) {
4642 set_samples_per_pixel (vc.samples_per_pixel);
4645 if (vc.pending & VisualChange::TimeOrigin) {
4646 double new_time_origin = sample_to_pixel_unrounded (vc.time_origin);
4647 set_horizontal_position (new_time_origin);
4650 if (vc.pending & VisualChange::YOrigin) {
4651 vertical_adjustment.set_value (vc.y_origin);
4655 * Now the canvas is in the final state before render the canvas items that
4656 * support the Item::prepare_for_render interface can calculate the correct
4657 * item to visible canvas intersection.
4659 if (vc.pending & VisualChange::ZoomLevel) {
4660 on_samples_per_pixel_changed ();
4662 compute_fixed_ruler_scale ();
4664 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4665 update_tempo_based_rulers ();
4668 if (!(vc.pending & VisualChange::ZoomLevel)) {
4670 * If the canvas is not being zoomed then the canvas items will not change
4671 * and cause Item::prepare_for_render to be called so do it here manually.
4673 * Not ideal, but I can't think of a better solution atm.
4675 _track_canvas->prepare_for_render();
4678 // If we are only scrolling vertically there is no need to update these
4679 if (vc.pending != VisualChange::YOrigin) {
4680 update_fixed_rulers ();
4681 redisplay_tempo (true);
4684 update_video_timeline();
4686 _summary->set_overlays_dirty ();
4689 struct EditorOrderTimeAxisSorter {
4690 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4691 return a->order () < b->order ();
4696 Editor::sort_track_selection (TrackViewList& sel)
4698 EditorOrderTimeAxisSorter cmp;
4703 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4706 framepos_t where = 0;
4707 EditPoint ep = _edit_point;
4709 if (Profile->get_mixbus()) {
4710 if (ep == EditAtSelectedMarker) {
4711 ep = EditAtPlayhead;
4715 if (from_outside_canvas && (ep == EditAtMouse)) {
4716 ep = EditAtPlayhead;
4717 } else if (from_context_menu && (ep == EditAtMouse)) {
4718 return canvas_event_sample (&context_click_event, 0, 0);
4721 if (entered_marker) {
4722 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4723 return entered_marker->position();
4726 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4727 ep = EditAtSelectedMarker;
4730 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4731 ep = EditAtPlayhead;
4734 MusicFrame snap_mf (0, 0);
4737 case EditAtPlayhead:
4738 if (_dragging_playhead && _control_scroll_target) {
4739 where = *_control_scroll_target;
4741 where = _session->audible_frame();
4743 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4746 case EditAtSelectedMarker:
4747 if (!selection->markers.empty()) {
4749 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4752 where = loc->start();
4756 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4764 if (!mouse_frame (where, ignored)) {
4765 /* XXX not right but what can we do ? */
4768 snap_mf.frame = where;
4770 where = snap_mf.frame;
4771 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4779 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4781 if (!_session) return;
4783 begin_reversible_command (cmd);
4787 if ((tll = transport_loop_location()) == 0) {
4788 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4789 XMLNode &before = _session->locations()->get_state();
4790 _session->locations()->add (loc, true);
4791 _session->set_auto_loop_location (loc);
4792 XMLNode &after = _session->locations()->get_state();
4793 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4795 XMLNode &before = tll->get_state();
4796 tll->set_hidden (false, this);
4797 tll->set (start, end);
4798 XMLNode &after = tll->get_state();
4799 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4802 commit_reversible_command ();
4806 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4808 if (!_session) return;
4810 begin_reversible_command (cmd);
4814 if ((tpl = transport_punch_location()) == 0) {
4815 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4816 XMLNode &before = _session->locations()->get_state();
4817 _session->locations()->add (loc, true);
4818 _session->set_auto_punch_location (loc);
4819 XMLNode &after = _session->locations()->get_state();
4820 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4822 XMLNode &before = tpl->get_state();
4823 tpl->set_hidden (false, this);
4824 tpl->set (start, end);
4825 XMLNode &after = tpl->get_state();
4826 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4829 commit_reversible_command ();
4832 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4833 * @param rs List to which found regions are added.
4834 * @param where Time to look at.
4835 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4838 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4840 const TrackViewList* tracks;
4843 tracks = &track_views;
4848 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4850 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4853 boost::shared_ptr<Track> tr;
4854 boost::shared_ptr<Playlist> pl;
4856 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4858 boost::shared_ptr<RegionList> regions = pl->regions_at (
4859 (framepos_t) floor ( (double) where * tr->speed()));
4861 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4862 RegionView* rv = rtv->view()->find_view (*i);
4873 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4875 const TrackViewList* tracks;
4878 tracks = &track_views;
4883 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4884 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4886 boost::shared_ptr<Track> tr;
4887 boost::shared_ptr<Playlist> pl;
4889 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4891 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4892 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4894 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4896 RegionView* rv = rtv->view()->find_view (*i);
4907 /** Get regions using the following method:
4909 * Make a region list using:
4910 * (a) any selected regions
4911 * (b) the intersection of any selected tracks and the edit point(*)
4912 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4914 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4916 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4920 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4922 RegionSelection regions;
4924 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4925 regions.add (entered_regionview);
4927 regions = selection->regions;
4930 if ( regions.empty() ) {
4931 TrackViewList tracks = selection->tracks;
4933 if (!tracks.empty()) {
4934 /* no region selected or entered, but some selected tracks:
4935 * act on all regions on the selected tracks at the edit point
4937 framepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
4938 get_regions_at(regions, where, tracks);
4945 /** Get regions using the following method:
4947 * Make a region list using:
4948 * (a) any selected regions
4949 * (b) the intersection of any selected tracks and the edit point(*)
4950 * (c) if neither exists, then whatever region is under the mouse
4952 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4954 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4957 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4959 RegionSelection regions;
4961 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4962 regions.add (entered_regionview);
4964 regions = selection->regions;
4967 if ( regions.empty() ) {
4968 TrackViewList tracks = selection->tracks;
4970 if (!tracks.empty()) {
4971 /* no region selected or entered, but some selected tracks:
4972 * act on all regions on the selected tracks at the edit point
4974 get_regions_at(regions, pos, tracks);
4981 /** Start with regions that are selected, or the entered regionview if none are selected.
4982 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4983 * of the regions that we started with.
4987 Editor::get_regions_from_selection_and_entered () const
4989 RegionSelection regions = selection->regions;
4991 if (regions.empty() && entered_regionview) {
4992 regions.add (entered_regionview);
4999 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
5001 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5002 RouteTimeAxisView* rtav;
5004 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5005 boost::shared_ptr<Playlist> pl;
5006 std::vector<boost::shared_ptr<Region> > results;
5007 boost::shared_ptr<Track> tr;
5009 if ((tr = rtav->track()) == 0) {
5014 if ((pl = (tr->playlist())) != 0) {
5015 boost::shared_ptr<Region> r = pl->region_by_id (id);
5017 RegionView* rv = rtav->view()->find_view (r);
5019 regions.push_back (rv);
5028 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5031 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5032 MidiTimeAxisView* mtav;
5034 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5036 mtav->get_per_region_note_selection (selection);
5043 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5045 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5047 RouteTimeAxisView* tatv;
5049 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5051 boost::shared_ptr<Playlist> pl;
5052 vector<boost::shared_ptr<Region> > results;
5054 boost::shared_ptr<Track> tr;
5056 if ((tr = tatv->track()) == 0) {
5061 if ((pl = (tr->playlist())) != 0) {
5062 if (src_comparison) {
5063 pl->get_source_equivalent_regions (region, results);
5065 pl->get_region_list_equivalent_regions (region, results);
5069 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5070 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5071 regions.push_back (marv);
5080 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
5082 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5083 RouteTimeAxisView* tatv;
5084 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5085 if (!tatv->track()) {
5088 RegionView* marv = tatv->view()->find_view (region);
5098 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5100 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5101 RouteTimeAxisView* rtav;
5102 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5103 if (rtav->route() == route) {
5112 Editor::show_rhythm_ferret ()
5114 if (rhythm_ferret == 0) {
5115 rhythm_ferret = new RhythmFerret(*this);
5118 rhythm_ferret->set_session (_session);
5119 rhythm_ferret->show ();
5120 rhythm_ferret->present ();
5124 Editor::first_idle ()
5126 MessageDialog* dialog = 0;
5128 if (track_views.size() > 1) {
5129 Timers::TimerSuspender t;
5130 dialog = new MessageDialog (
5131 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5135 ARDOUR_UI::instance()->flush_pending (60);
5138 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5142 /* now that all regionviews should exist, setup region selection */
5146 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5147 /* this is cumulative: rs is NOT cleared each time */
5148 get_regionviews_by_id (*pr, rs);
5151 selection->set (rs);
5153 // first idle adds route children (automation tracks), so we need to redisplay here
5154 _routes->redisplay ();
5158 if (_session->undo_depth() == 0) {
5159 undo_action->set_sensitive(false);
5161 redo_action->set_sensitive(false);
5162 begin_selection_op_history ();
5168 Editor::_idle_resize (gpointer arg)
5170 return ((Editor*)arg)->idle_resize ();
5174 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5176 if (resize_idle_id < 0) {
5177 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5178 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5179 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5181 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5182 _pending_resize_amount = 0;
5185 /* make a note of the smallest resulting height, so that we can clamp the
5186 lower limit at TimeAxisView::hSmall */
5188 int32_t min_resulting = INT32_MAX;
5190 _pending_resize_amount += h;
5191 _pending_resize_view = view;
5193 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5195 if (selection->tracks.contains (_pending_resize_view)) {
5196 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5197 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5201 if (min_resulting < 0) {
5206 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5207 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5211 /** Handle pending resizing of tracks */
5213 Editor::idle_resize ()
5215 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5217 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5218 selection->tracks.contains (_pending_resize_view)) {
5220 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5221 if (*i != _pending_resize_view) {
5222 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5227 _pending_resize_amount = 0;
5228 _group_tabs->set_dirty ();
5229 resize_idle_id = -1;
5237 ENSURE_GUI_THREAD (*this, &Editor::located);
5240 playhead_cursor->set_position (_session->audible_frame ());
5241 if (_follow_playhead && !_pending_initial_locate) {
5242 reset_x_origin_to_follow_playhead ();
5246 _pending_locate_request = false;
5247 _pending_initial_locate = false;
5248 _last_update_time = 0;
5252 Editor::region_view_added (RegionView * rv)
5254 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5256 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5257 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5258 if (rv->region()->id () == (*rnote).first) {
5259 mrv->select_notes ((*rnote).second);
5260 selection->pending_midi_note_selection.erase(rnote);
5266 _summary->set_background_dirty ();
5270 Editor::region_view_removed ()
5272 _summary->set_background_dirty ();
5276 Editor::axis_view_by_stripable (boost::shared_ptr<Stripable> s) const
5278 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5279 if ((*j)->stripable() == s) {
5288 Editor::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
5290 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5291 if ((*j)->control() == c) {
5295 TimeAxisView::Children kids = (*j)->get_child_list ();
5297 for (TimeAxisView::Children::iterator k = kids.begin(); k != kids.end(); ++k) {
5298 if ((*k)->control() == c) {
5308 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5312 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5313 TimeAxisView* tv = time_axis_view_from_stripable (*i);
5323 Editor::suspend_route_redisplay ()
5326 _routes->suspend_redisplay();
5331 Editor::resume_route_redisplay ()
5334 _routes->redisplay(); // queue redisplay
5335 _routes->resume_redisplay();
5340 Editor::add_vcas (VCAList& vlist)
5344 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5345 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5348 add_stripables (sl);
5352 Editor::add_routes (RouteList& rlist)
5356 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5360 add_stripables (sl);
5364 Editor::add_stripables (StripableList& sl)
5366 list<TimeAxisView*> new_views;
5367 boost::shared_ptr<VCA> v;
5368 boost::shared_ptr<Route> r;
5369 TrackViewList new_selection;
5370 bool from_scratch = (track_views.size() == 0);
5372 sl.sort (Stripable::Sorter());
5374 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5376 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5378 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5380 new_views.push_back (vtv);
5382 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5384 if (r->is_auditioner() || r->is_monitor()) {
5388 RouteTimeAxisView* rtv;
5389 DataType dt = r->input()->default_type();
5391 if (dt == ARDOUR::DataType::AUDIO) {
5392 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5394 } else if (dt == ARDOUR::DataType::MIDI) {
5395 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5398 throw unknown_type();
5401 new_views.push_back (rtv);
5402 track_views.push_back (rtv);
5403 new_selection.push_back (rtv);
5405 rtv->effective_gain_display ();
5407 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5408 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5412 if (new_views.size() > 0) {
5413 _routes->time_axis_views_added (new_views);
5414 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5417 /* note: !new_selection.empty() means that we got some routes rather
5421 if (!from_scratch && !new_selection.empty()) {
5422 selection->set (new_selection);
5423 begin_selection_op_history();
5426 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5427 show_editor_mixer (true);
5430 editor_list_button.set_sensitive (true);
5434 Editor::timeaxisview_deleted (TimeAxisView *tv)
5436 if (tv == entered_track) {
5440 if (_session && _session->deletion_in_progress()) {
5441 /* the situation is under control */
5445 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5447 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5449 _routes->route_removed (tv);
5451 TimeAxisView::Children c = tv->get_child_list ();
5452 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5453 if (entered_track == i->get()) {
5458 /* remove it from the list of track views */
5460 TrackViewList::iterator i;
5462 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5463 i = track_views.erase (i);
5466 /* update whatever the current mixer strip is displaying, if revelant */
5468 boost::shared_ptr<Route> route;
5471 route = rtav->route ();
5474 if (current_mixer_strip && current_mixer_strip->route() == route) {
5476 TimeAxisView* next_tv;
5478 if (track_views.empty()) {
5480 } else if (i == track_views.end()) {
5481 next_tv = track_views.front();
5486 // skip VCAs (cannot be selected, n/a in editor-mixer)
5487 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5488 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5489 next_tv = track_views.front();
5491 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5492 /* just in case: no master, only a VCA remains */
5498 set_selected_mixer_strip (*next_tv);
5500 /* make the editor mixer strip go away setting the
5501 * button to inactive (which also unticks the menu option)
5504 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5510 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5515 if (apply_to_selection) {
5516 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5518 TrackSelection::iterator j = i;
5521 hide_track_in_display (*i, false);
5526 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5528 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5529 // this will hide the mixer strip
5530 set_selected_mixer_strip (*tv);
5533 _routes->hide_track_in_display (*tv);
5538 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5543 _routes->show_track_in_display (*tv);
5544 if (move_into_view) {
5545 ensure_time_axis_view_is_visible (*tv, false);
5550 Editor::sync_track_view_list_and_routes ()
5552 track_views = TrackViewList (_routes->views ());
5554 _summary->set_background_dirty();
5555 _group_tabs->set_dirty ();
5557 return false; // do not call again (until needed)
5561 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5563 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5568 /** Find a RouteTimeAxisView by the ID of its route */
5570 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5572 RouteTimeAxisView* v;
5574 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5575 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5576 if(v->route()->id() == id) {
5586 Editor::fit_route_group (RouteGroup *g)
5588 TrackViewList ts = axis_views_from_routes (g->route_list ());
5593 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5595 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5598 _session->cancel_audition ();
5602 if (_session->is_auditioning()) {
5603 _session->cancel_audition ();
5604 if (r == last_audition_region) {
5609 _session->audition_region (r);
5610 last_audition_region = r;
5615 Editor::hide_a_region (boost::shared_ptr<Region> r)
5617 r->set_hidden (true);
5621 Editor::show_a_region (boost::shared_ptr<Region> r)
5623 r->set_hidden (false);
5627 Editor::audition_region_from_region_list ()
5629 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5633 Editor::hide_region_from_region_list ()
5635 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5639 Editor::show_region_in_region_list ()
5641 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5645 Editor::step_edit_status_change (bool yn)
5648 start_step_editing ();
5650 stop_step_editing ();
5655 Editor::start_step_editing ()
5657 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5661 Editor::stop_step_editing ()
5663 step_edit_connection.disconnect ();
5667 Editor::check_step_edit ()
5669 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5670 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5672 mtv->check_step_edit ();
5676 return true; // do it again, till we stop
5680 Editor::scroll_press (Direction dir)
5682 ++_scroll_callbacks;
5684 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5685 /* delay the first auto-repeat */
5691 scroll_backward (1);
5699 scroll_up_one_track ();
5703 scroll_down_one_track ();
5707 /* do hacky auto-repeat */
5708 if (!_scroll_connection.connected ()) {
5710 _scroll_connection = Glib::signal_timeout().connect (
5711 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5714 _scroll_callbacks = 0;
5721 Editor::scroll_release ()
5723 _scroll_connection.disconnect ();
5726 /** Queue a change for the Editor viewport x origin to follow the playhead */
5728 Editor::reset_x_origin_to_follow_playhead ()
5730 framepos_t const frame = playhead_cursor->current_frame ();
5732 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5734 if (_session->transport_speed() < 0) {
5736 if (frame > (current_page_samples() / 2)) {
5737 center_screen (frame-(current_page_samples()/2));
5739 center_screen (current_page_samples()/2);
5746 if (frame < leftmost_frame) {
5748 if (_session->transport_rolling()) {
5749 /* rolling; end up with the playhead at the right of the page */
5750 l = frame - current_page_samples ();
5752 /* not rolling: end up with the playhead 1/4 of the way along the page */
5753 l = frame - current_page_samples() / 4;
5757 if (_session->transport_rolling()) {
5758 /* rolling: end up with the playhead on the left of the page */
5761 /* not rolling: end up with the playhead 3/4 of the way along the page */
5762 l = frame - 3 * current_page_samples() / 4;
5770 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5776 Editor::super_rapid_screen_update ()
5778 if (!_session || !_session->engine().running()) {
5782 /* METERING / MIXER STRIPS */
5784 /* update track meters, if required */
5785 if (contents().is_mapped() && meters_running) {
5786 RouteTimeAxisView* rtv;
5787 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5788 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5789 rtv->fast_update ();
5794 /* and any current mixer strip */
5795 if (current_mixer_strip) {
5796 current_mixer_strip->fast_update ();
5799 /* PLAYHEAD AND VIEWPORT */
5801 /* There are a few reasons why we might not update the playhead / viewport stuff:
5803 * 1. we don't update things when there's a pending locate request, otherwise
5804 * when the editor requests a locate there is a chance that this method
5805 * will move the playhead before the locate request is processed, causing
5807 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5808 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5810 if (_pending_locate_request || !_session->transport_rolling ()) {
5811 _last_update_time = 0;
5815 if (_dragging_playhead) {
5816 _last_update_time = 0;
5820 bool latent_locate = false;
5821 framepos_t frame = _session->audible_frame (&latent_locate);
5822 const int64_t now = g_get_monotonic_time ();
5825 if (_last_update_time > 0) {
5826 const double ds = (now - _last_update_time) * _session->transport_speed() * _session->nominal_frame_rate () * 1e-6;
5827 framepos_t guess = playhead_cursor->current_frame () + rint (ds);
5828 err = frame - guess;
5830 guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update)
5831 _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2
5834 printf ("eng: %ld gui:%ld (%+6.1f) diff: %6.1f (err: %7.2f)\n",
5836 err, _err_screen_engine);
5841 _err_screen_engine = 0;
5844 if (err > 8192 || latent_locate) {
5845 // in case of x-runs or freewheeling
5846 _last_update_time = 0;
5848 _last_update_time = now;
5851 if (playhead_cursor->current_frame () == frame) {
5855 playhead_cursor->set_position (frame);
5857 if (_session->requested_return_frame() >= 0) {
5858 _last_update_time = 0;
5862 if (!_follow_playhead || pending_visual_change.being_handled) {
5863 /* We only do this if we aren't already
5864 * handling a visual change (ie if
5865 * pending_visual_change.being_handled is
5866 * false) so that these requests don't stack
5867 * up there are too many of them to handle in
5873 if (!_stationary_playhead) {
5874 reset_x_origin_to_follow_playhead ();
5876 framepos_t const frame = playhead_cursor->current_frame ();
5877 double target = ((double)frame - (double)current_page_samples() / 2.0);
5878 if (target <= 0.0) {
5881 // compare to EditorCursor::set_position()
5882 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5883 double const new_pos = sample_to_pixel_unrounded (target);
5884 if (rint (new_pos) != rint (old_pos)) {
5885 reset_x_origin (pixel_to_sample (new_pos));
5892 Editor::session_going_away ()
5894 _have_idled = false;
5896 _session_connections.drop_connections ();
5898 super_rapid_screen_update_connection.disconnect ();
5900 selection->clear ();
5901 cut_buffer->clear ();
5903 clicked_regionview = 0;
5904 clicked_axisview = 0;
5905 clicked_routeview = 0;
5906 entered_regionview = 0;
5908 _last_update_time = 0;
5911 playhead_cursor->hide ();
5913 /* rip everything out of the list displays */
5917 _route_groups->clear ();
5919 /* do this first so that deleting a track doesn't reset cms to null
5920 and thus cause a leak.
5923 if (current_mixer_strip) {
5924 if (current_mixer_strip->get_parent() != 0) {
5925 global_hpacker.remove (*current_mixer_strip);
5927 delete current_mixer_strip;
5928 current_mixer_strip = 0;
5931 /* delete all trackviews */
5933 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5936 track_views.clear ();
5938 nudge_clock->set_session (0);
5940 editor_list_button.set_active(false);
5941 editor_list_button.set_sensitive(false);
5943 /* clear tempo/meter rulers */
5944 remove_metric_marks ();
5946 clear_marker_display ();
5951 stop_step_editing ();
5955 /* get rid of any existing editor mixer strip */
5957 WindowTitle title(Glib::get_application_name());
5958 title += _("Editor");
5960 own_window()->set_title (title.get_string());
5963 SessionHandlePtr::session_going_away ();
5967 Editor::trigger_script (int i)
5969 LuaInstance::instance()-> call_action (i);
5973 Editor::show_editor_list (bool yn)
5976 _editor_list_vbox.show ();
5978 _editor_list_vbox.hide ();
5983 Editor::change_region_layering_order (bool from_context_menu)
5985 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5987 if (!clicked_routeview) {
5988 if (layering_order_editor) {
5989 layering_order_editor->hide ();
5994 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
6000 boost::shared_ptr<Playlist> pl = track->playlist();
6006 if (layering_order_editor == 0) {
6007 layering_order_editor = new RegionLayeringOrderEditor (*this);
6010 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
6011 layering_order_editor->maybe_present ();
6015 Editor::update_region_layering_order_editor ()
6017 if (layering_order_editor && layering_order_editor->is_visible ()) {
6018 change_region_layering_order (true);
6023 Editor::setup_fade_images ()
6025 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
6026 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
6027 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
6028 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
6029 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
6031 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
6032 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
6033 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
6034 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
6035 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
6039 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
6041 Editor::action_menu_item (std::string const & name)
6043 Glib::RefPtr<Action> a = editor_actions->get_action (name);
6046 return *manage (a->create_menu_item ());
6050 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
6052 EventBox* b = manage (new EventBox);
6053 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
6054 Label* l = manage (new Label (name));
6058 _the_notebook.append_page (widget, *b);
6062 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6064 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6065 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6068 if (ev->type == GDK_2BUTTON_PRESS) {
6070 /* double-click on a notebook tab shrinks or expands the notebook */
6072 if (_notebook_shrunk) {
6073 if (pre_notebook_shrink_pane_width) {
6074 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6076 _notebook_shrunk = false;
6078 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6080 /* this expands the LHS of the edit pane to cover the notebook
6081 PAGE but leaves the tabs visible.
6083 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6084 _notebook_shrunk = true;
6092 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6094 using namespace Menu_Helpers;
6096 MenuList& items = _control_point_context_menu.items ();
6099 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6100 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6101 if (!can_remove_control_point (item)) {
6102 items.back().set_sensitive (false);
6105 _control_point_context_menu.popup (event->button.button, event->button.time);
6109 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6111 using namespace Menu_Helpers;
6113 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6118 /* We need to get the selection here and pass it to the operations, since
6119 popping up the menu will cause a region leave event which clears
6120 entered_regionview. */
6122 MidiRegionView& mrv = note->region_view();
6123 const RegionSelection rs = get_regions_from_selection_and_entered ();
6124 const uint32_t sel_size = mrv.selection_size ();
6126 MenuList& items = _note_context_menu.items();
6130 items.push_back(MenuElem(_("Delete"),
6131 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6134 items.push_back(MenuElem(_("Edit..."),
6135 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6136 if (sel_size != 1) {
6137 items.back().set_sensitive (false);
6140 items.push_back(MenuElem(_("Transpose..."),
6141 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6144 items.push_back(MenuElem(_("Legatize"),
6145 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6147 items.back().set_sensitive (false);
6150 items.push_back(MenuElem(_("Quantize..."),
6151 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6153 items.push_back(MenuElem(_("Remove Overlap"),
6154 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6156 items.back().set_sensitive (false);
6159 items.push_back(MenuElem(_("Transform..."),
6160 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6162 _note_context_menu.popup (event->button.button, event->button.time);
6166 Editor::zoom_vertical_modifier_released()
6168 _stepping_axis_view = 0;
6172 Editor::ui_parameter_changed (string parameter)
6174 if (parameter == "icon-set") {
6175 while (!_cursor_stack.empty()) {
6176 _cursor_stack.pop_back();
6178 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6179 _cursor_stack.push_back(_cursors->grabber);
6180 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6181 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6183 } else if (parameter == "draggable-playhead") {
6184 if (_verbose_cursor) {
6185 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6191 Editor::use_own_window (bool and_fill_it)
6193 bool new_window = !own_window();
6195 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6197 if (win && new_window) {
6198 win->set_name ("EditorWindow");
6200 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6202 // win->signal_realize().connect (*this, &Editor::on_realize);
6203 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6204 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6205 win->set_data ("ardour-bindings", bindings);
6210 DisplaySuspender ds;
6211 contents().show_all ();
6213 /* XXX: this is a bit unfortunate; it would probably
6214 be nicer if we could just call show () above rather
6215 than needing the show_all ()
6218 /* re-hide stuff if necessary */
6219 editor_list_button_toggled ();
6220 parameter_changed ("show-summary");
6221 parameter_changed ("show-group-tabs");
6222 parameter_changed ("show-zoom-tools");
6224 /* now reset all audio_time_axis heights, because widgets might need
6230 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6231 tv = (static_cast<TimeAxisView*>(*i));
6232 tv->reset_height ();
6235 if (current_mixer_strip) {
6236 current_mixer_strip->hide_things ();
6237 current_mixer_strip->parameter_changed ("mixer-element-visibility");