2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include <gtkmm2ext/keyboard.h>
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
68 #include "ardour/analysis_graph.h"
69 #include "ardour/audio_track.h"
70 #include "ardour/audioengine.h"
71 #include "ardour/audioregion.h"
72 #include "ardour/lmath.h"
73 #include "ardour/location.h"
74 #include "ardour/profile.h"
75 #include "ardour/route_group.h"
76 #include "ardour/session_playlists.h"
77 #include "ardour/tempo.h"
78 #include "ardour/utils.h"
79 #include "ardour/vca_manager.h"
81 #include "canvas/debug.h"
82 #include "canvas/text.h"
84 #include "control_protocol/control_protocol.h"
87 #include "analysis_window.h"
88 #include "audio_clock.h"
89 #include "audio_region_view.h"
90 #include "audio_streamview.h"
91 #include "audio_time_axis.h"
92 #include "automation_time_axis.h"
93 #include "bundle_manager.h"
94 #include "crossfade_edit.h"
98 #include "editor_cursors.h"
99 #include "editor_drag.h"
100 #include "editor_group_tabs.h"
101 #include "editor_locations.h"
102 #include "editor_regions.h"
103 #include "editor_route_groups.h"
104 #include "editor_routes.h"
105 #include "editor_snapshots.h"
106 #include "editor_summary.h"
107 #include "export_report.h"
108 #include "global_port_matrix.h"
109 #include "gui_object.h"
110 #include "gui_thread.h"
111 #include "keyboard.h"
112 #include "keyeditor.h"
113 #include "luainstance.h"
115 #include "midi_region_view.h"
116 #include "midi_time_axis.h"
117 #include "mixer_strip.h"
118 #include "mixer_ui.h"
119 #include "mouse_cursors.h"
120 #include "note_base.h"
121 #include "playlist_selector.h"
122 #include "public_editor.h"
123 #include "quantize_dialog.h"
124 #include "region_layering_order_editor.h"
125 #include "rgb_macros.h"
126 #include "rhythm_ferret.h"
127 #include "selection.h"
128 #include "simple_progress_dialog.h"
130 #include "tempo_lines.h"
131 #include "time_axis_view.h"
133 #include "tooltips.h"
134 #include "ui_config.h"
136 #include "vca_time_axis.h"
137 #include "verbose_cursor.h"
142 using namespace ARDOUR;
143 using namespace ARDOUR_UI_UTILS;
146 using namespace Glib;
147 using namespace Gtkmm2ext;
148 using namespace Editing;
150 using PBD::internationalize;
152 using Gtkmm2ext::Keyboard;
154 double Editor::timebar_height = 15.0;
156 static const gchar *_snap_type_strings[] = {
190 static const gchar *_snap_mode_strings[] = {
197 static const gchar *_edit_point_strings[] = {
204 static const gchar *_edit_mode_strings[] = {
212 static const gchar *_zoom_focus_strings[] = {
222 #ifdef USE_RUBBERBAND
223 static const gchar *_rb_opt_strings[] = {
226 N_("Balanced multitimbral mixture"),
227 N_("Unpitched percussion with stable notes"),
228 N_("Crisp monophonic instrumental"),
229 N_("Unpitched solo percussion"),
230 N_("Resample without preserving pitch"),
235 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
238 pane_size_watcher (Paned* pane)
240 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
244 Quartz: impossible to access
246 so stop that by preventing it from ever getting too narrow. 35
247 pixels is basically a rough guess at the tab width.
252 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
254 gint pos = pane->get_position ();
256 if (pos > max_width_of_lhs) {
257 pane->set_position (max_width_of_lhs);
262 : PublicEditor (global_hpacker)
263 , editor_mixer_strip_width (Wide)
264 , constructed (false)
265 , _playlist_selector (0)
266 , no_save_visual (false)
268 , samples_per_pixel (2048)
269 , zoom_focus (ZoomFocusPlayhead)
270 , mouse_mode (MouseObject)
271 , pre_internal_snap_type (SnapToBeat)
272 , pre_internal_snap_mode (SnapOff)
273 , internal_snap_type (SnapToBeat)
274 , internal_snap_mode (SnapOff)
275 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
276 , _notebook_shrunk (false)
277 , location_marker_color (0)
278 , location_range_color (0)
279 , location_loop_color (0)
280 , location_punch_color (0)
281 , location_cd_marker_color (0)
283 , _show_marker_lines (false)
284 , clicked_axisview (0)
285 , clicked_routeview (0)
286 , clicked_regionview (0)
287 , clicked_selection (0)
288 , clicked_control_point (0)
289 , button_release_can_deselect (true)
290 , _mouse_changed_selection (false)
291 , region_edit_menu_split_item (0)
292 , region_edit_menu_split_multichannel_item (0)
293 , track_region_edit_playlist_menu (0)
294 , track_edit_playlist_submenu (0)
295 , track_selection_edit_playlist_submenu (0)
296 , _popup_region_menu_item (0)
298 , _track_canvas_viewport (0)
299 , within_track_canvas (false)
300 , _verbose_cursor (0)
304 , range_marker_group (0)
305 , transport_marker_group (0)
306 , cd_marker_group (0)
307 , _time_markers_group (0)
308 , hv_scroll_group (0)
310 , cursor_scroll_group (0)
311 , no_scroll_group (0)
312 , _trackview_group (0)
313 , _drag_motion_group (0)
314 , _canvas_drop_zone (0)
315 , no_ruler_shown_update (false)
316 , ruler_grabbed_widget (0)
318 , minsec_mark_interval (0)
319 , minsec_mark_modulo (0)
321 , timecode_mark_modulo (0)
322 , timecode_nmarks (0)
323 , _samples_ruler_interval (0)
326 , bbt_bar_helper_on (0)
327 , bbt_accent_modulo (0)
332 , visible_timebars (0)
333 , editor_ruler_menu (0)
337 , range_marker_bar (0)
338 , transport_marker_bar (0)
340 , minsec_label (_("Mins:Secs"))
341 , bbt_label (_("Bars:Beats"))
342 , timecode_label (_("Timecode"))
343 , samples_label (_("Samples"))
344 , tempo_label (_("Tempo"))
345 , meter_label (_("Meter"))
346 , mark_label (_("Location Markers"))
347 , range_mark_label (_("Range Markers"))
348 , transport_mark_label (_("Loop/Punch Ranges"))
349 , cd_mark_label (_("CD Markers"))
350 , videotl_label (_("Video Timeline"))
352 , playhead_cursor (0)
353 , edit_packer (4, 4, true)
354 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
355 , horizontal_adjustment (0.0, 0.0, 1e16)
356 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
357 , controls_layout (unused_adjustment, vertical_adjustment)
358 , _scroll_callbacks (0)
359 , _visible_canvas_width (0)
360 , _visible_canvas_height (0)
361 , _full_canvas_height (0)
362 , edit_controls_left_menu (0)
363 , edit_controls_right_menu (0)
364 , last_update_frame (0)
365 , cut_buffer_start (0)
366 , cut_buffer_length (0)
367 , button_bindings (0)
371 , current_interthread_info (0)
372 , analysis_window (0)
373 , select_new_marker (false)
375 , scrubbing_direction (0)
376 , scrub_reversals (0)
377 , scrub_reverse_distance (0)
378 , have_pending_keyboard_selection (false)
379 , pending_keyboard_selection_start (0)
380 , _snap_type (SnapToBeat)
381 , _snap_mode (SnapOff)
382 , snap_threshold (5.0)
383 , ignore_gui_changes (false)
384 , _drags (new DragManager (this))
386 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
387 , _dragging_playhead (false)
388 , _dragging_edit_point (false)
389 , _show_measures (true)
390 , _follow_playhead (true)
391 , _stationary_playhead (false)
394 , global_rect_group (0)
395 , time_line_group (0)
396 , tempo_marker_menu (0)
397 , meter_marker_menu (0)
399 , range_marker_menu (0)
400 , transport_marker_menu (0)
401 , new_transport_marker_menu (0)
403 , marker_menu_item (0)
404 , bbt_beat_subdivision (4)
405 , _visible_track_count (-1)
406 , toolbar_selection_clock_table (2,3)
407 , automation_mode_button (_("mode"))
408 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
409 , selection (new Selection (this))
410 , cut_buffer (new Selection (this))
411 , _selection_memento (new SelectionMemento())
412 , _all_region_actions_sensitized (false)
413 , _ignore_region_action (false)
414 , _last_region_menu_was_main (false)
415 , _ignore_follow_edits (false)
416 , cd_marker_bar_drag_rect (0)
417 , range_bar_drag_rect (0)
418 , transport_bar_drag_rect (0)
419 , transport_bar_range_rect (0)
420 , transport_bar_preroll_rect (0)
421 , transport_bar_postroll_rect (0)
422 , transport_loop_range_rect (0)
423 , transport_punch_range_rect (0)
424 , transport_punchin_line (0)
425 , transport_punchout_line (0)
426 , transport_preroll_rect (0)
427 , transport_postroll_rect (0)
429 , rubberband_rect (0)
435 , autoscroll_horizontal_allowed (false)
436 , autoscroll_vertical_allowed (false)
438 , autoscroll_widget (0)
439 , show_gain_after_trim (false)
440 , selection_op_cmd_depth (0)
441 , selection_op_history_it (0)
442 , no_save_instant (false)
444 , current_mixer_strip (0)
445 , show_editor_mixer_when_tracks_arrive (false)
446 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
447 , current_stepping_trackview (0)
448 , last_track_height_step_timestamp (0)
450 , entered_regionview (0)
451 , clear_entered_track (false)
452 , _edit_point (EditAtMouse)
453 , meters_running (false)
455 , _have_idled (false)
456 , resize_idle_id (-1)
457 , _pending_resize_amount (0)
458 , _pending_resize_view (0)
459 , _pending_locate_request (false)
460 , _pending_initial_locate (false)
464 , layering_order_editor (0)
465 , _last_cut_copy_source_track (0)
466 , _region_selection_change_updates_region_list (true)
468 , _following_mixer_selection (false)
469 , _control_point_toggled_on_press (false)
470 , _stepping_axis_view (0)
471 , quantize_dialog (0)
472 , _main_menu_disabler (0)
473 , myactions (X_("editor"))
475 /* we are a singleton */
477 PublicEditor::_instance = this;
481 last_event_time.tv_sec = 0;
482 last_event_time.tv_usec = 0;
484 selection_op_history.clear();
487 snap_type_strings = I18N (_snap_type_strings);
488 snap_mode_strings = I18N (_snap_mode_strings);
489 zoom_focus_strings = I18N (_zoom_focus_strings);
490 edit_mode_strings = I18N (_edit_mode_strings);
491 edit_point_strings = I18N (_edit_point_strings);
492 #ifdef USE_RUBBERBAND
493 rb_opt_strings = I18N (_rb_opt_strings);
497 build_edit_mode_menu();
498 build_zoom_focus_menu();
499 build_track_count_menu();
500 build_snap_mode_menu();
501 build_snap_type_menu();
502 build_edit_point_menu();
504 location_marker_color = UIConfiguration::instance().color ("location marker");
505 location_range_color = UIConfiguration::instance().color ("location range");
506 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
507 location_loop_color = UIConfiguration::instance().color ("location loop");
508 location_punch_color = UIConfiguration::instance().color ("location punch");
510 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
512 TimeAxisView::setup_sizes ();
513 ArdourMarker::setup_sizes (timebar_height);
514 TempoCurve::setup_sizes (timebar_height);
516 bbt_label.set_name ("EditorRulerLabel");
517 bbt_label.set_size_request (-1, (int)timebar_height);
518 bbt_label.set_alignment (1.0, 0.5);
519 bbt_label.set_padding (5,0);
521 bbt_label.set_no_show_all();
522 minsec_label.set_name ("EditorRulerLabel");
523 minsec_label.set_size_request (-1, (int)timebar_height);
524 minsec_label.set_alignment (1.0, 0.5);
525 minsec_label.set_padding (5,0);
526 minsec_label.hide ();
527 minsec_label.set_no_show_all();
528 timecode_label.set_name ("EditorRulerLabel");
529 timecode_label.set_size_request (-1, (int)timebar_height);
530 timecode_label.set_alignment (1.0, 0.5);
531 timecode_label.set_padding (5,0);
532 timecode_label.hide ();
533 timecode_label.set_no_show_all();
534 samples_label.set_name ("EditorRulerLabel");
535 samples_label.set_size_request (-1, (int)timebar_height);
536 samples_label.set_alignment (1.0, 0.5);
537 samples_label.set_padding (5,0);
538 samples_label.hide ();
539 samples_label.set_no_show_all();
541 tempo_label.set_name ("EditorRulerLabel");
542 tempo_label.set_size_request (-1, (int)timebar_height);
543 tempo_label.set_alignment (1.0, 0.5);
544 tempo_label.set_padding (5,0);
546 tempo_label.set_no_show_all();
548 meter_label.set_name ("EditorRulerLabel");
549 meter_label.set_size_request (-1, (int)timebar_height);
550 meter_label.set_alignment (1.0, 0.5);
551 meter_label.set_padding (5,0);
553 meter_label.set_no_show_all();
555 if (Profile->get_trx()) {
556 mark_label.set_text (_("Markers"));
558 mark_label.set_name ("EditorRulerLabel");
559 mark_label.set_size_request (-1, (int)timebar_height);
560 mark_label.set_alignment (1.0, 0.5);
561 mark_label.set_padding (5,0);
563 mark_label.set_no_show_all();
565 cd_mark_label.set_name ("EditorRulerLabel");
566 cd_mark_label.set_size_request (-1, (int)timebar_height);
567 cd_mark_label.set_alignment (1.0, 0.5);
568 cd_mark_label.set_padding (5,0);
569 cd_mark_label.hide();
570 cd_mark_label.set_no_show_all();
572 videotl_bar_height = 4;
573 videotl_label.set_name ("EditorRulerLabel");
574 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
575 videotl_label.set_alignment (1.0, 0.5);
576 videotl_label.set_padding (5,0);
577 videotl_label.hide();
578 videotl_label.set_no_show_all();
580 range_mark_label.set_name ("EditorRulerLabel");
581 range_mark_label.set_size_request (-1, (int)timebar_height);
582 range_mark_label.set_alignment (1.0, 0.5);
583 range_mark_label.set_padding (5,0);
584 range_mark_label.hide();
585 range_mark_label.set_no_show_all();
587 transport_mark_label.set_name ("EditorRulerLabel");
588 transport_mark_label.set_size_request (-1, (int)timebar_height);
589 transport_mark_label.set_alignment (1.0, 0.5);
590 transport_mark_label.set_padding (5,0);
591 transport_mark_label.hide();
592 transport_mark_label.set_no_show_all();
594 initialize_canvas ();
596 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
598 _summary = new EditorSummary (this);
600 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
601 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
603 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
605 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
606 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
608 edit_controls_vbox.set_spacing (0);
609 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
610 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
612 HBox* h = manage (new HBox);
613 _group_tabs = new EditorGroupTabs (this);
614 if (!ARDOUR::Profile->get_trx()) {
615 h->pack_start (*_group_tabs, PACK_SHRINK);
617 h->pack_start (edit_controls_vbox);
618 controls_layout.add (*h);
620 controls_layout.set_name ("EditControlsBase");
621 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
622 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
623 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
625 _cursors = new MouseCursors;
626 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
627 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
629 /* Push default cursor to ever-present bottom of cursor stack. */
630 push_canvas_cursor(_cursors->grabber);
632 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
634 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
635 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
636 pad_line_1->set_outline_color (0xFF0000FF);
642 edit_packer.set_col_spacings (0);
643 edit_packer.set_row_spacings (0);
644 edit_packer.set_homogeneous (false);
645 edit_packer.set_border_width (0);
646 edit_packer.set_name ("EditorWindow");
648 time_bars_event_box.add (time_bars_vbox);
649 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
650 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
652 /* labels for the time bars */
653 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
655 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
657 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
659 bottom_hbox.set_border_width (2);
660 bottom_hbox.set_spacing (3);
662 _route_groups = new EditorRouteGroups (this);
663 _routes = new EditorRoutes (this);
664 _regions = new EditorRegions (this);
665 _snapshots = new EditorSnapshots (this);
666 _locations = new EditorLocations (this);
668 /* these are static location signals */
670 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
671 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
672 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
674 add_notebook_page (_("Regions"), _regions->widget ());
675 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
676 add_notebook_page (_("Snapshots"), _snapshots->widget ());
677 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
678 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
680 _the_notebook.set_show_tabs (true);
681 _the_notebook.set_scrollable (true);
682 _the_notebook.popup_disable ();
683 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
684 _the_notebook.show_all ();
686 _notebook_shrunk = false;
688 editor_summary_pane.pack1(edit_packer);
690 Button* summary_arrows_left_left = manage (new Button);
691 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
692 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
693 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
695 Button* summary_arrows_left_right = manage (new Button);
696 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
697 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
698 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
700 VBox* summary_arrows_left = manage (new VBox);
701 summary_arrows_left->pack_start (*summary_arrows_left_left);
702 summary_arrows_left->pack_start (*summary_arrows_left_right);
704 Button* summary_arrows_right_up = manage (new Button);
705 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
706 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
707 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
709 Button* summary_arrows_right_down = manage (new Button);
710 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
711 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
712 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
714 VBox* summary_arrows_right = manage (new VBox);
715 summary_arrows_right->pack_start (*summary_arrows_right_up);
716 summary_arrows_right->pack_start (*summary_arrows_right_down);
718 Frame* summary_frame = manage (new Frame);
719 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
721 summary_frame->add (*_summary);
722 summary_frame->show ();
724 _summary_hbox.pack_start (*summary_arrows_left, false, false);
725 _summary_hbox.pack_start (*summary_frame, true, true);
726 _summary_hbox.pack_start (*summary_arrows_right, false, false);
728 if (!ARDOUR::Profile->get_trx()) {
729 editor_summary_pane.pack2 (_summary_hbox);
732 edit_pane.pack1 (editor_summary_pane, true, true);
733 if (!ARDOUR::Profile->get_trx()) {
734 edit_pane.pack2 (_the_notebook, false, true);
737 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
739 /* XXX: editor_summary_pane might need similar to the edit_pane */
741 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
743 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
744 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
746 top_hbox.pack_start (toolbar_frame);
748 HBox *hbox = manage (new HBox);
749 hbox->pack_start (edit_pane, true, true);
751 global_vpacker.pack_start (top_hbox, false, false);
752 global_vpacker.pack_start (*hbox, true, true);
753 global_hpacker.pack_start (global_vpacker, true, true);
755 /* need to show the "contents" widget so that notebook will show if tab is switched to
758 global_hpacker.show ();
760 /* register actions now so that set_state() can find them and set toggles/checks etc */
767 _playlist_selector = new PlaylistSelector();
768 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
770 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
774 nudge_forward_button.set_name ("nudge button");
775 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
777 nudge_backward_button.set_name ("nudge button");
778 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
780 fade_context_menu.set_name ("ArdourContextMenu");
782 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
784 /* allow external control surfaces/protocols to do various things */
786 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
787 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
788 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
789 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
790 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
791 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
792 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
793 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
794 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
795 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
796 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
797 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
798 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
799 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
801 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
802 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
803 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
804 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
805 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
807 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
811 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
813 /* problematic: has to return a value and thus cannot be x-thread */
815 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
817 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
818 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
820 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
822 _ignore_region_action = false;
823 _last_region_menu_was_main = false;
824 _popup_region_menu_item = 0;
826 _ignore_follow_edits = false;
828 _show_marker_lines = false;
830 /* Button bindings */
832 button_bindings = new Bindings ("editor-mouse");
834 XMLNode* node = button_settings();
836 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
837 button_bindings->load_operation (**i);
843 /* grab current parameter state */
844 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
845 UIConfiguration::instance().map_parameters (pc);
847 setup_fade_images ();
849 LuaInstance::instance(); // instantiate
850 LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &Editor::set_script_action_name));
857 delete button_bindings;
859 delete _route_groups;
860 delete _track_canvas_viewport;
863 delete quantize_dialog;
869 delete _playlist_selector;
871 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
877 Editor::button_settings () const
879 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
880 XMLNode* node = find_named_node (*settings, X_("Buttons"));
883 node = new XMLNode (X_("Buttons"));
890 Editor::get_smart_mode () const
892 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
896 Editor::catch_vanishing_regionview (RegionView *rv)
898 /* note: the selection will take care of the vanishing
899 audioregionview by itself.
902 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
906 if (clicked_regionview == rv) {
907 clicked_regionview = 0;
910 if (entered_regionview == rv) {
911 set_entered_regionview (0);
914 if (!_all_region_actions_sensitized) {
915 sensitize_all_region_actions (true);
920 Editor::set_entered_regionview (RegionView* rv)
922 if (rv == entered_regionview) {
926 if (entered_regionview) {
927 entered_regionview->exited ();
930 entered_regionview = rv;
932 if (entered_regionview != 0) {
933 entered_regionview->entered ();
936 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
937 /* This RegionView entry might have changed what region actions
938 are allowed, so sensitize them all in case a key is pressed.
940 sensitize_all_region_actions (true);
945 Editor::set_entered_track (TimeAxisView* tav)
948 entered_track->exited ();
954 entered_track->entered ();
959 Editor::instant_save ()
961 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
966 _session->add_instant_xml(get_state());
968 Config->add_instant_xml(get_state());
973 Editor::control_vertical_zoom_in_all ()
975 tav_zoom_smooth (false, true);
979 Editor::control_vertical_zoom_out_all ()
981 tav_zoom_smooth (true, true);
985 Editor::control_vertical_zoom_in_selected ()
987 tav_zoom_smooth (false, false);
991 Editor::control_vertical_zoom_out_selected ()
993 tav_zoom_smooth (true, false);
997 Editor::control_view (uint32_t view)
999 goto_visual_state (view);
1003 Editor::control_unselect ()
1005 selection->clear_tracks ();
1009 Editor::control_select (PresentationInfo::global_order_t global_order, Selection::Operation op)
1011 /* handles the (static) signal from the ControlProtocol class that
1012 * requests setting the selected track to a given RID
1019 PresentationInfo::Flag select_flags;
1021 if (global_order & ~0xffffffff) {
1022 /* some flags are set, so the PresentationInfo constructor
1025 select_flags = PresentationInfo::Flag (0);
1027 /* no type flags set in the global order ID, so assume caller
1028 * wants to select a Route
1030 select_flags = PresentationInfo::Route;
1033 PresentationInfo pi (global_order, select_flags);
1034 boost::shared_ptr<Stripable> s = _session->get_remote_nth_stripable (pi.group_order(), pi.flags());
1036 /* selected object may not be a Route */
1038 boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route> (s);
1044 TimeAxisView* tav = axis_view_from_route (r);
1048 case Selection::Add:
1049 selection->add (tav);
1051 case Selection::Toggle:
1052 selection->toggle (tav);
1054 case Selection::Extend:
1056 case Selection::Set:
1057 selection->set (tav);
1061 selection->clear_tracks ();
1066 Editor::control_step_tracks_up ()
1068 scroll_tracks_up_line ();
1072 Editor::control_step_tracks_down ()
1074 scroll_tracks_down_line ();
1078 Editor::control_scroll (float fraction)
1080 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1086 double step = fraction * current_page_samples();
1089 _control_scroll_target is an optional<T>
1091 it acts like a pointer to an framepos_t, with
1092 a operator conversion to boolean to check
1093 that it has a value could possibly use
1094 playhead_cursor->current_frame to store the
1095 value and a boolean in the class to know
1096 when it's out of date
1099 if (!_control_scroll_target) {
1100 _control_scroll_target = _session->transport_frame();
1101 _dragging_playhead = true;
1104 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1105 *_control_scroll_target = 0;
1106 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1107 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1109 *_control_scroll_target += (framepos_t) trunc (step);
1112 /* move visuals, we'll catch up with it later */
1114 playhead_cursor->set_position (*_control_scroll_target);
1115 UpdateAllTransportClocks (*_control_scroll_target);
1117 if (*_control_scroll_target > (current_page_samples() / 2)) {
1118 /* try to center PH in window */
1119 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1125 Now we do a timeout to actually bring the session to the right place
1126 according to the playhead. This is to avoid reading disk buffers on every
1127 call to control_scroll, which is driven by ScrollTimeline and therefore
1128 probably by a control surface wheel which can generate lots of events.
1130 /* cancel the existing timeout */
1132 control_scroll_connection.disconnect ();
1134 /* add the next timeout */
1136 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1140 Editor::deferred_control_scroll (framepos_t /*target*/)
1142 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1143 // reset for next stream
1144 _control_scroll_target = boost::none;
1145 _dragging_playhead = false;
1150 Editor::access_action (std::string action_group, std::string action_item)
1156 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1159 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1167 Editor::on_realize ()
1171 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1172 start_lock_event_timing ();
1177 Editor::start_lock_event_timing ()
1179 /* check if we should lock the GUI every 30 seconds */
1181 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1185 Editor::generic_event_handler (GdkEvent* ev)
1188 case GDK_BUTTON_PRESS:
1189 case GDK_BUTTON_RELEASE:
1190 case GDK_MOTION_NOTIFY:
1192 case GDK_KEY_RELEASE:
1193 if (contents().is_mapped()) {
1194 gettimeofday (&last_event_time, 0);
1198 case GDK_LEAVE_NOTIFY:
1199 switch (ev->crossing.detail) {
1200 case GDK_NOTIFY_UNKNOWN:
1201 case GDK_NOTIFY_INFERIOR:
1202 case GDK_NOTIFY_ANCESTOR:
1204 case GDK_NOTIFY_VIRTUAL:
1205 case GDK_NOTIFY_NONLINEAR:
1206 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1207 /* leaving window, so reset focus, thus ending any and
1208 all text entry operations.
1210 reset_focus (&contents());
1223 Editor::lock_timeout_callback ()
1225 struct timeval now, delta;
1227 gettimeofday (&now, 0);
1229 timersub (&now, &last_event_time, &delta);
1231 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1233 /* don't call again. Returning false will effectively
1234 disconnect us from the timer callback.
1236 unlock() will call start_lock_event_timing() to get things
1246 Editor::map_position_change (framepos_t frame)
1248 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1250 if (_session == 0) {
1254 if (_follow_playhead) {
1255 center_screen (frame);
1258 playhead_cursor->set_position (frame);
1262 Editor::center_screen (framepos_t frame)
1264 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1266 /* if we're off the page, then scroll.
1269 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1270 center_screen_internal (frame, page);
1275 Editor::center_screen_internal (framepos_t frame, float page)
1280 frame -= (framepos_t) page;
1285 reset_x_origin (frame);
1290 Editor::update_title ()
1292 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1294 if (!own_window()) {
1299 bool dirty = _session->dirty();
1301 string session_name;
1303 if (_session->snap_name() != _session->name()) {
1304 session_name = _session->snap_name();
1306 session_name = _session->name();
1310 session_name = "*" + session_name;
1313 WindowTitle title(session_name);
1314 title += S_("Window|Editor");
1315 title += Glib::get_application_name();
1316 own_window()->set_title (title.get_string());
1318 /* ::session_going_away() will have taken care of it */
1323 Editor::set_session (Session *t)
1325 SessionHandlePtr::set_session (t);
1331 _playlist_selector->set_session (_session);
1332 nudge_clock->set_session (_session);
1333 _summary->set_session (_session);
1334 _group_tabs->set_session (_session);
1335 _route_groups->set_session (_session);
1336 _regions->set_session (_session);
1337 _snapshots->set_session (_session);
1338 _routes->set_session (_session);
1339 _locations->set_session (_session);
1341 if (rhythm_ferret) {
1342 rhythm_ferret->set_session (_session);
1345 if (analysis_window) {
1346 analysis_window->set_session (_session);
1350 sfbrowser->set_session (_session);
1353 compute_fixed_ruler_scale ();
1355 /* Make sure we have auto loop and auto punch ranges */
1357 Location* loc = _session->locations()->auto_loop_location();
1359 loc->set_name (_("Loop"));
1362 loc = _session->locations()->auto_punch_location();
1365 loc->set_name (_("Punch"));
1368 refresh_location_display ();
1370 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1371 the selected Marker; this needs the LocationMarker list to be available.
1373 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1374 set_state (*node, Stateful::loading_state_version);
1376 /* catch up with the playhead */
1378 _session->request_locate (playhead_cursor->current_frame ());
1379 _pending_initial_locate = true;
1383 /* These signals can all be emitted by a non-GUI thread. Therefore the
1384 handlers for them must not attempt to directly interact with the GUI,
1385 but use PBD::Signal<T>::connect() which accepts an event loop
1386 ("context") where the handler will be asked to run.
1389 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1390 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1391 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1392 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1393 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1394 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1395 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1396 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::marker_position_changed, this), gui_context());
1397 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1398 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1399 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1400 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1401 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1402 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1403 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1405 playhead_cursor->show ();
1407 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1408 Config->map_parameters (pc);
1409 _session->config.map_parameters (pc);
1411 restore_ruler_visibility ();
1412 //tempo_map_changed (PropertyChange (0));
1413 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1415 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1416 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1419 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1420 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1423 switch (_snap_type) {
1424 case SnapToRegionStart:
1425 case SnapToRegionEnd:
1426 case SnapToRegionSync:
1427 case SnapToRegionBoundary:
1428 build_region_boundary_cache ();
1435 /* register for undo history */
1436 _session->register_with_memento_command_factory(id(), this);
1437 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1439 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1441 LuaInstance::instance()->set_session(_session);
1443 start_updating_meters ();
1447 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1449 if (a->get_name() == "RegionMenu") {
1450 /* When the main menu's region menu is opened, we setup the actions so that they look right
1451 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1452 so we resensitize all region actions when the entered regionview or the region selection
1453 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1454 happens after the region context menu is opened. So we set a flag here, too.
1458 sensitize_the_right_region_actions ();
1459 _last_region_menu_was_main = true;
1464 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1466 using namespace Menu_Helpers;
1468 void (Editor::*emf)(FadeShape);
1469 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1472 images = &_xfade_in_images;
1473 emf = &Editor::set_fade_in_shape;
1475 images = &_xfade_out_images;
1476 emf = &Editor::set_fade_out_shape;
1481 _("Linear (for highly correlated material)"),
1482 *(*images)[FadeLinear],
1483 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1487 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1491 _("Constant power"),
1492 *(*images)[FadeConstantPower],
1493 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1496 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1501 *(*images)[FadeSymmetric],
1502 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1506 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1511 *(*images)[FadeSlow],
1512 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1515 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1520 *(*images)[FadeFast],
1521 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1524 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1527 /** Pop up a context menu for when the user clicks on a start crossfade */
1529 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1531 using namespace Menu_Helpers;
1532 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1537 MenuList& items (xfade_in_context_menu.items());
1540 if (arv->audio_region()->fade_in_active()) {
1541 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1543 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1546 items.push_back (SeparatorElem());
1547 fill_xfade_menu (items, true);
1549 xfade_in_context_menu.popup (button, time);
1552 /** Pop up a context menu for when the user clicks on an end crossfade */
1554 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1556 using namespace Menu_Helpers;
1557 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1562 MenuList& items (xfade_out_context_menu.items());
1565 if (arv->audio_region()->fade_out_active()) {
1566 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1568 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1571 items.push_back (SeparatorElem());
1572 fill_xfade_menu (items, false);
1574 xfade_out_context_menu.popup (button, time);
1578 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1580 using namespace Menu_Helpers;
1581 Menu* (Editor::*build_menu_function)();
1584 switch (item_type) {
1586 case RegionViewName:
1587 case RegionViewNameHighlight:
1588 case LeftFrameHandle:
1589 case RightFrameHandle:
1590 if (with_selection) {
1591 build_menu_function = &Editor::build_track_selection_context_menu;
1593 build_menu_function = &Editor::build_track_region_context_menu;
1598 if (with_selection) {
1599 build_menu_function = &Editor::build_track_selection_context_menu;
1601 build_menu_function = &Editor::build_track_context_menu;
1606 if (clicked_routeview->track()) {
1607 build_menu_function = &Editor::build_track_context_menu;
1609 build_menu_function = &Editor::build_track_bus_context_menu;
1614 /* probably shouldn't happen but if it does, we don't care */
1618 menu = (this->*build_menu_function)();
1619 menu->set_name ("ArdourContextMenu");
1621 /* now handle specific situations */
1623 switch (item_type) {
1625 case RegionViewName:
1626 case RegionViewNameHighlight:
1627 case LeftFrameHandle:
1628 case RightFrameHandle:
1629 if (!with_selection) {
1630 if (region_edit_menu_split_item) {
1631 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1632 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1634 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1637 if (region_edit_menu_split_multichannel_item) {
1638 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1639 region_edit_menu_split_multichannel_item->set_sensitive (true);
1641 region_edit_menu_split_multichannel_item->set_sensitive (false);
1654 /* probably shouldn't happen but if it does, we don't care */
1658 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1660 /* Bounce to disk */
1662 using namespace Menu_Helpers;
1663 MenuList& edit_items = menu->items();
1665 edit_items.push_back (SeparatorElem());
1667 switch (clicked_routeview->audio_track()->freeze_state()) {
1668 case AudioTrack::NoFreeze:
1669 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1672 case AudioTrack::Frozen:
1673 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1676 case AudioTrack::UnFrozen:
1677 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1683 if (item_type == StreamItem && clicked_routeview) {
1684 clicked_routeview->build_underlay_menu(menu);
1687 /* When the region menu is opened, we setup the actions so that they look right
1690 sensitize_the_right_region_actions ();
1691 _last_region_menu_was_main = false;
1693 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1694 menu->popup (button, time);
1698 Editor::build_track_context_menu ()
1700 using namespace Menu_Helpers;
1702 MenuList& edit_items = track_context_menu.items();
1705 add_dstream_context_items (edit_items);
1706 return &track_context_menu;
1710 Editor::build_track_bus_context_menu ()
1712 using namespace Menu_Helpers;
1714 MenuList& edit_items = track_context_menu.items();
1717 add_bus_context_items (edit_items);
1718 return &track_context_menu;
1722 Editor::build_track_region_context_menu ()
1724 using namespace Menu_Helpers;
1725 MenuList& edit_items = track_region_context_menu.items();
1728 /* we've just cleared the track region context menu, so the menu that these
1729 two items were on will have disappeared; stop them dangling.
1731 region_edit_menu_split_item = 0;
1732 region_edit_menu_split_multichannel_item = 0;
1734 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1737 boost::shared_ptr<Track> tr;
1738 boost::shared_ptr<Playlist> pl;
1740 if ((tr = rtv->track())) {
1741 add_region_context_items (edit_items, tr);
1745 add_dstream_context_items (edit_items);
1747 return &track_region_context_menu;
1751 Editor::loudness_analyze_region_selection ()
1756 Selection& s (PublicEditor::instance ().get_selection ());
1757 RegionSelection ars = s.regions;
1758 ARDOUR::AnalysisGraph ag (_session);
1759 framecnt_t total_work = 0;
1761 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1762 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1766 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1769 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1770 total_work += arv->region ()->length ();
1773 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1775 ag.set_total_frames (total_work);
1776 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1779 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1780 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1784 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1788 ag.analyze_region (ar);
1791 if (!ag.canceled ()) {
1792 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1798 Editor::loudness_analyze_range_selection ()
1803 Selection& s (PublicEditor::instance ().get_selection ());
1804 TimeSelection ts = s.time;
1805 ARDOUR::AnalysisGraph ag (_session);
1806 framecnt_t total_work = 0;
1808 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1809 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1813 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1817 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1818 total_work += j->length ();
1822 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1824 ag.set_total_frames (total_work);
1825 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1828 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1829 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1833 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1837 ag.analyze_range (rui->route (), pl, ts);
1840 if (!ag.canceled ()) {
1841 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1847 Editor::spectral_analyze_region_selection ()
1849 if (analysis_window == 0) {
1850 analysis_window = new AnalysisWindow();
1853 analysis_window->set_session(_session);
1855 analysis_window->show_all();
1858 analysis_window->set_regionmode();
1859 analysis_window->analyze();
1861 analysis_window->present();
1865 Editor::spectral_analyze_range_selection()
1867 if (analysis_window == 0) {
1868 analysis_window = new AnalysisWindow();
1871 analysis_window->set_session(_session);
1873 analysis_window->show_all();
1876 analysis_window->set_rangemode();
1877 analysis_window->analyze();
1879 analysis_window->present();
1883 Editor::build_track_selection_context_menu ()
1885 using namespace Menu_Helpers;
1886 MenuList& edit_items = track_selection_context_menu.items();
1887 edit_items.clear ();
1889 add_selection_context_items (edit_items);
1890 // edit_items.push_back (SeparatorElem());
1891 // add_dstream_context_items (edit_items);
1893 return &track_selection_context_menu;
1897 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1899 using namespace Menu_Helpers;
1901 /* OK, stick the region submenu at the top of the list, and then add
1905 RegionSelection rs = get_regions_from_selection_and_entered ();
1907 string::size_type pos = 0;
1908 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1910 /* we have to hack up the region name because "_" has a special
1911 meaning for menu titles.
1914 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1915 menu_item_name.replace (pos, 1, "__");
1919 if (_popup_region_menu_item == 0) {
1920 _popup_region_menu_item = new MenuItem (menu_item_name);
1921 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1922 _popup_region_menu_item->show ();
1924 _popup_region_menu_item->set_label (menu_item_name);
1927 /* No latering allowed in later is higher layering model */
1928 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1929 if (act && Config->get_layer_model() == LaterHigher) {
1930 act->set_sensitive (false);
1932 act->set_sensitive (true);
1935 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1937 edit_items.push_back (*_popup_region_menu_item);
1938 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1939 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1941 edit_items.push_back (SeparatorElem());
1944 /** Add context menu items relevant to selection ranges.
1945 * @param edit_items List to add the items to.
1948 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1950 using namespace Menu_Helpers;
1952 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1953 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1955 edit_items.push_back (SeparatorElem());
1956 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1958 edit_items.push_back (SeparatorElem());
1959 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1960 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1962 edit_items.push_back (SeparatorElem());
1964 edit_items.push_back (
1966 _("Move Range Start to Previous Region Boundary"),
1967 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1971 edit_items.push_back (
1973 _("Move Range Start to Next Region Boundary"),
1974 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1978 edit_items.push_back (
1980 _("Move Range End to Previous Region Boundary"),
1981 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1985 edit_items.push_back (
1987 _("Move Range End to Next Region Boundary"),
1988 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1992 edit_items.push_back (SeparatorElem());
1993 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1994 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1996 edit_items.push_back (SeparatorElem());
1997 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1999 edit_items.push_back (SeparatorElem());
2000 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
2001 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
2002 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
2004 edit_items.push_back (SeparatorElem());
2005 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
2007 edit_items.push_back (SeparatorElem());
2008 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
2009 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
2011 edit_items.push_back (SeparatorElem());
2012 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
2013 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
2014 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
2015 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
2016 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
2017 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
2018 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2024 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2026 using namespace Menu_Helpers;
2030 Menu *play_menu = manage (new Menu);
2031 MenuList& play_items = play_menu->items();
2032 play_menu->set_name ("ArdourContextMenu");
2034 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2035 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2036 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2037 play_items.push_back (SeparatorElem());
2038 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2040 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2044 Menu *select_menu = manage (new Menu);
2045 MenuList& select_items = select_menu->items();
2046 select_menu->set_name ("ArdourContextMenu");
2048 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2049 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2050 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2051 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2052 select_items.push_back (SeparatorElem());
2053 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2054 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2055 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2056 select_items.push_back (SeparatorElem());
2057 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2058 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2059 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2060 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2061 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2062 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2063 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2065 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2069 Menu *cutnpaste_menu = manage (new Menu);
2070 MenuList& cutnpaste_items = cutnpaste_menu->items();
2071 cutnpaste_menu->set_name ("ArdourContextMenu");
2073 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2074 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2075 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2077 cutnpaste_items.push_back (SeparatorElem());
2079 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2080 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2082 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2084 /* Adding new material */
2086 edit_items.push_back (SeparatorElem());
2087 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2088 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2092 Menu *nudge_menu = manage (new Menu());
2093 MenuList& nudge_items = nudge_menu->items();
2094 nudge_menu->set_name ("ArdourContextMenu");
2096 edit_items.push_back (SeparatorElem());
2097 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2098 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2099 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2100 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2102 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2106 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2108 using namespace Menu_Helpers;
2112 Menu *play_menu = manage (new Menu);
2113 MenuList& play_items = play_menu->items();
2114 play_menu->set_name ("ArdourContextMenu");
2116 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2117 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2118 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2122 Menu *select_menu = manage (new Menu);
2123 MenuList& select_items = select_menu->items();
2124 select_menu->set_name ("ArdourContextMenu");
2126 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2127 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2128 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2129 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2130 select_items.push_back (SeparatorElem());
2131 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2132 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2133 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2134 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2136 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2140 Menu *cutnpaste_menu = manage (new Menu);
2141 MenuList& cutnpaste_items = cutnpaste_menu->items();
2142 cutnpaste_menu->set_name ("ArdourContextMenu");
2144 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2145 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2146 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2148 Menu *nudge_menu = manage (new Menu());
2149 MenuList& nudge_items = nudge_menu->items();
2150 nudge_menu->set_name ("ArdourContextMenu");
2152 edit_items.push_back (SeparatorElem());
2153 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2154 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2155 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2156 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2158 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2162 Editor::snap_type() const
2168 Editor::snap_musical() const
2170 switch (_snap_type) {
2171 case SnapToBeatDiv128:
2172 case SnapToBeatDiv64:
2173 case SnapToBeatDiv32:
2174 case SnapToBeatDiv28:
2175 case SnapToBeatDiv24:
2176 case SnapToBeatDiv20:
2177 case SnapToBeatDiv16:
2178 case SnapToBeatDiv14:
2179 case SnapToBeatDiv12:
2180 case SnapToBeatDiv10:
2181 case SnapToBeatDiv8:
2182 case SnapToBeatDiv7:
2183 case SnapToBeatDiv6:
2184 case SnapToBeatDiv5:
2185 case SnapToBeatDiv4:
2186 case SnapToBeatDiv3:
2187 case SnapToBeatDiv2:
2199 Editor::snap_mode() const
2205 Editor::set_snap_to (SnapType st)
2207 unsigned int snap_ind = (unsigned int)st;
2209 if (internal_editing()) {
2210 internal_snap_type = st;
2212 pre_internal_snap_type = st;
2217 if (snap_ind > snap_type_strings.size() - 1) {
2219 _snap_type = (SnapType)snap_ind;
2222 string str = snap_type_strings[snap_ind];
2224 if (str != snap_type_selector.get_text()) {
2225 snap_type_selector.set_text (str);
2230 switch (_snap_type) {
2231 case SnapToBeatDiv128:
2232 case SnapToBeatDiv64:
2233 case SnapToBeatDiv32:
2234 case SnapToBeatDiv28:
2235 case SnapToBeatDiv24:
2236 case SnapToBeatDiv20:
2237 case SnapToBeatDiv16:
2238 case SnapToBeatDiv14:
2239 case SnapToBeatDiv12:
2240 case SnapToBeatDiv10:
2241 case SnapToBeatDiv8:
2242 case SnapToBeatDiv7:
2243 case SnapToBeatDiv6:
2244 case SnapToBeatDiv5:
2245 case SnapToBeatDiv4:
2246 case SnapToBeatDiv3:
2247 case SnapToBeatDiv2: {
2248 std::vector<TempoMap::BBTPoint> grid;
2249 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
2250 compute_bbt_ruler_scale (grid, leftmost_frame, leftmost_frame + current_page_samples());
2251 update_tempo_based_rulers (grid);
2255 case SnapToRegionStart:
2256 case SnapToRegionEnd:
2257 case SnapToRegionSync:
2258 case SnapToRegionBoundary:
2259 build_region_boundary_cache ();
2267 redisplay_tempo (false);
2269 SnapChanged (); /* EMIT SIGNAL */
2273 Editor::set_snap_mode (SnapMode mode)
2275 string str = snap_mode_strings[(int)mode];
2277 if (internal_editing()) {
2278 internal_snap_mode = mode;
2280 pre_internal_snap_mode = mode;
2285 if (str != snap_mode_selector.get_text ()) {
2286 snap_mode_selector.set_text (str);
2293 Editor::set_edit_point_preference (EditPoint ep, bool force)
2295 bool changed = (_edit_point != ep);
2298 if (Profile->get_mixbus())
2299 if (ep == EditAtSelectedMarker)
2300 ep = EditAtPlayhead;
2302 string str = edit_point_strings[(int)ep];
2303 if (str != edit_point_selector.get_text ()) {
2304 edit_point_selector.set_text (str);
2307 update_all_enter_cursors();
2309 if (!force && !changed) {
2313 const char* action=NULL;
2315 switch (_edit_point) {
2316 case EditAtPlayhead:
2317 action = "edit-at-playhead";
2319 case EditAtSelectedMarker:
2320 action = "edit-at-marker";
2323 action = "edit-at-mouse";
2327 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2329 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2333 bool in_track_canvas;
2335 if (!mouse_frame (foo, in_track_canvas)) {
2336 in_track_canvas = false;
2339 reset_canvas_action_sensitivity (in_track_canvas);
2345 Editor::set_state (const XMLNode& node, int version)
2347 XMLProperty const * prop;
2349 PBD::Unwinder<bool> nsi (no_save_instant, true);
2351 Tabbable::set_state (node, version);
2353 if (_session && (prop = node.property ("playhead"))) {
2355 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2357 playhead_cursor->set_position (pos);
2359 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2360 playhead_cursor->set_position (0);
2363 playhead_cursor->set_position (0);
2366 if ((prop = node.property ("mixer-width"))) {
2367 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2370 if ((prop = node.property ("zoom-focus"))) {
2371 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2374 if ((prop = node.property ("zoom"))) {
2375 /* older versions of ardour used floating point samples_per_pixel */
2376 double f = PBD::atof (prop->value());
2377 reset_zoom (llrintf (f));
2379 reset_zoom (samples_per_pixel);
2382 if ((prop = node.property ("visible-track-count"))) {
2383 set_visible_track_count (PBD::atoi (prop->value()));
2386 if ((prop = node.property ("snap-to"))) {
2387 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2388 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2391 if ((prop = node.property ("snap-mode"))) {
2392 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2393 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2394 * snap_mode_selection_done() will only mark an already active item as active
2395 * which does not trigger set_text().
2397 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2400 if ((prop = node.property ("internal-snap-to"))) {
2401 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2404 if ((prop = node.property ("internal-snap-mode"))) {
2405 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2408 if ((prop = node.property ("pre-internal-snap-to"))) {
2409 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2412 if ((prop = node.property ("pre-internal-snap-mode"))) {
2413 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2416 if ((prop = node.property ("mouse-mode"))) {
2417 MouseMode m = str2mousemode(prop->value());
2418 set_mouse_mode (m, true);
2420 set_mouse_mode (MouseObject, true);
2423 if ((prop = node.property ("left-frame")) != 0) {
2425 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2429 reset_x_origin (pos);
2433 if ((prop = node.property ("y-origin")) != 0) {
2434 reset_y_origin (atof (prop->value ()));
2437 if ((prop = node.property ("join-object-range"))) {
2438 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2439 bool yn = string_is_affirmative (prop->value());
2441 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2442 tact->set_active (!yn);
2443 tact->set_active (yn);
2445 set_mouse_mode(mouse_mode, true);
2448 if ((prop = node.property ("edit-point"))) {
2449 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2452 if ((prop = node.property ("show-measures"))) {
2453 bool yn = string_is_affirmative (prop->value());
2454 _show_measures = yn;
2457 if ((prop = node.property ("follow-playhead"))) {
2458 bool yn = string_is_affirmative (prop->value());
2459 set_follow_playhead (yn);
2462 if ((prop = node.property ("stationary-playhead"))) {
2463 bool yn = string_is_affirmative (prop->value());
2464 set_stationary_playhead (yn);
2467 if ((prop = node.property ("region-list-sort-type"))) {
2468 RegionListSortType st;
2469 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2472 if ((prop = node.property ("show-editor-mixer"))) {
2474 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2477 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2478 bool yn = string_is_affirmative (prop->value());
2480 /* do it twice to force the change */
2482 tact->set_active (!yn);
2483 tact->set_active (yn);
2486 if ((prop = node.property ("show-editor-list"))) {
2488 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2491 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2492 bool yn = string_is_affirmative (prop->value());
2494 /* do it twice to force the change */
2496 tact->set_active (!yn);
2497 tact->set_active (yn);
2500 if ((prop = node.property (X_("editor-list-page")))) {
2501 _the_notebook.set_current_page (atoi (prop->value ()));
2504 if ((prop = node.property (X_("show-marker-lines")))) {
2505 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2507 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2508 bool yn = string_is_affirmative (prop->value ());
2510 tact->set_active (!yn);
2511 tact->set_active (yn);
2514 XMLNodeList children = node.children ();
2515 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2516 selection->set_state (**i, Stateful::current_state_version);
2517 _regions->set_state (**i);
2520 if ((prop = node.property ("maximised"))) {
2521 bool yn = string_is_affirmative (prop->value());
2522 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2524 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2525 bool fs = tact && tact->get_active();
2527 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2531 if ((prop = node.property ("nudge-clock-value"))) {
2533 sscanf (prop->value().c_str(), "%" PRId64, &f);
2534 nudge_clock->set (f);
2536 nudge_clock->set_mode (AudioClock::Timecode);
2537 nudge_clock->set (_session->frame_rate() * 5, true);
2542 * Not all properties may have been in XML, but
2543 * those that are linked to a private variable may need changing
2548 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2550 yn = _show_measures;
2551 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2552 /* do it twice to force the change */
2553 tact->set_active (!yn);
2554 tact->set_active (yn);
2557 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2558 yn = _follow_playhead;
2560 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2561 if (tact->get_active() != yn) {
2562 tact->set_active (yn);
2566 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2567 yn = _stationary_playhead;
2569 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2570 if (tact->get_active() != yn) {
2571 tact->set_active (yn);
2576 return LuaInstance::instance()->set_state(node);
2580 Editor::get_state ()
2582 XMLNode* node = new XMLNode (X_("Editor"));
2585 id().print (buf, sizeof (buf));
2586 node->add_property ("id", buf);
2588 node->add_child_nocopy (Tabbable::get_state());
2590 snprintf(buf,sizeof(buf), "%f", paned_position_as_fraction (edit_pane, false));
2591 node->add_property("edit-horizontal-pane-pos", string(buf));
2592 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2593 snprintf(buf,sizeof(buf), "%f", paned_position_as_fraction (editor_summary_pane, true));
2594 node->add_property("edit-vertical-pane-pos", string(buf));
2596 maybe_add_mixer_strip_width (*node);
2598 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2600 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2601 node->add_property ("zoom", buf);
2602 node->add_property ("snap-to", enum_2_string (_snap_type));
2603 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2604 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2605 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2606 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2607 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2608 node->add_property ("edit-point", enum_2_string (_edit_point));
2609 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2610 node->add_property ("visible-track-count", buf);
2612 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2613 node->add_property ("playhead", buf);
2614 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2615 node->add_property ("left-frame", buf);
2616 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2617 node->add_property ("y-origin", buf);
2619 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2620 node->add_property ("maximised", _maximised ? "yes" : "no");
2621 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2622 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2623 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2624 node->add_property ("mouse-mode", enum2str(mouse_mode));
2625 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2627 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2629 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2630 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2633 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2635 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2636 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2639 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2640 node->add_property (X_("editor-list-page"), buf);
2642 if (button_bindings) {
2643 XMLNode* bb = new XMLNode (X_("Buttons"));
2644 button_bindings->save (*bb);
2645 node->add_child_nocopy (*bb);
2648 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2650 node->add_child_nocopy (selection->get_state ());
2651 node->add_child_nocopy (_regions->get_state ());
2653 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2654 node->add_property ("nudge-clock-value", buf);
2656 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2657 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2662 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2663 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2665 * @return pair: TimeAxisView that y is over, layer index.
2667 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2668 * in stacked or expanded region display mode, otherwise 0.
2670 std::pair<TimeAxisView *, double>
2671 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2673 if (!trackview_relative_offset) {
2674 y -= _trackview_group->canvas_origin().y;
2678 return std::make_pair ( (TimeAxisView *) 0, 0);
2681 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2683 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2690 return std::make_pair ( (TimeAxisView *) 0, 0);
2693 /** Snap a position to the grid, if appropriate, taking into account current
2694 * grid settings and also the state of any snap modifier keys that may be pressed.
2695 * @param start Position to snap.
2696 * @param event Event to get current key modifier information from, or 0.
2699 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2701 if (!_session || !event) {
2705 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2706 if (_snap_mode == SnapOff) {
2707 snap_to_internal (start, direction, for_mark);
2710 if (_snap_mode != SnapOff) {
2711 snap_to_internal (start, direction, for_mark);
2712 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2713 /* SnapOff, but we pressed the snap_delta modifier */
2714 snap_to_internal (start, direction, for_mark);
2720 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2722 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2726 snap_to_internal (start, direction, for_mark, ensure_snap);
2730 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2732 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2733 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2735 switch (_snap_type) {
2736 case SnapToTimecodeFrame:
2737 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2738 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2739 /* start is already on a whole timecode frame, do nothing */
2740 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2741 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2743 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2747 case SnapToTimecodeSeconds:
2748 if (_session->config.get_timecode_offset_negative()) {
2749 start += _session->config.get_timecode_offset ();
2751 start -= _session->config.get_timecode_offset ();
2753 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2754 (start % one_timecode_second == 0)) {
2755 /* start is already on a whole second, do nothing */
2756 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2757 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2759 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2762 if (_session->config.get_timecode_offset_negative()) {
2763 start -= _session->config.get_timecode_offset ();
2765 start += _session->config.get_timecode_offset ();
2769 case SnapToTimecodeMinutes:
2770 if (_session->config.get_timecode_offset_negative()) {
2771 start += _session->config.get_timecode_offset ();
2773 start -= _session->config.get_timecode_offset ();
2775 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2776 (start % one_timecode_minute == 0)) {
2777 /* start is already on a whole minute, do nothing */
2778 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2779 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2781 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2783 if (_session->config.get_timecode_offset_negative()) {
2784 start -= _session->config.get_timecode_offset ();
2786 start += _session->config.get_timecode_offset ();
2790 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2791 abort(); /*NOTREACHED*/
2796 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2798 const framepos_t one_second = _session->frame_rate();
2799 const framepos_t one_minute = _session->frame_rate() * 60;
2800 framepos_t presnap = start;
2804 switch (_snap_type) {
2805 case SnapToTimecodeFrame:
2806 case SnapToTimecodeSeconds:
2807 case SnapToTimecodeMinutes:
2808 return timecode_snap_to_internal (start, direction, for_mark);
2811 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2812 start % (one_second/75) == 0) {
2813 /* start is already on a whole CD frame, do nothing */
2814 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2815 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2817 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2822 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2823 start % one_second == 0) {
2824 /* start is already on a whole second, do nothing */
2825 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2826 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2828 start = (framepos_t) floor ((double) start / one_second) * one_second;
2833 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2834 start % one_minute == 0) {
2835 /* start is already on a whole minute, do nothing */
2836 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2837 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2839 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2844 start = _session->tempo_map().round_to_bar (start, direction);
2848 start = _session->tempo_map().round_to_beat (start, direction);
2851 case SnapToBeatDiv128:
2852 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2854 case SnapToBeatDiv64:
2855 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2857 case SnapToBeatDiv32:
2858 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2860 case SnapToBeatDiv28:
2861 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2863 case SnapToBeatDiv24:
2864 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2866 case SnapToBeatDiv20:
2867 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2869 case SnapToBeatDiv16:
2870 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2872 case SnapToBeatDiv14:
2873 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2875 case SnapToBeatDiv12:
2876 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2878 case SnapToBeatDiv10:
2879 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2881 case SnapToBeatDiv8:
2882 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2884 case SnapToBeatDiv7:
2885 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2887 case SnapToBeatDiv6:
2888 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2890 case SnapToBeatDiv5:
2891 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2893 case SnapToBeatDiv4:
2894 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2896 case SnapToBeatDiv3:
2897 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2899 case SnapToBeatDiv2:
2900 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2908 _session->locations()->marks_either_side (start, before, after);
2910 if (before == max_framepos && after == max_framepos) {
2911 /* No marks to snap to, so just don't snap */
2913 } else if (before == max_framepos) {
2915 } else if (after == max_framepos) {
2917 } else if (before != max_framepos && after != max_framepos) {
2918 /* have before and after */
2919 if ((start - before) < (after - start)) {
2928 case SnapToRegionStart:
2929 case SnapToRegionEnd:
2930 case SnapToRegionSync:
2931 case SnapToRegionBoundary:
2932 if (!region_boundary_cache.empty()) {
2934 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2935 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2937 if (direction > 0) {
2938 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2940 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2943 if (next != region_boundary_cache.begin ()) {
2948 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2949 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2951 if (start > (p + n) / 2) {
2960 switch (_snap_mode) {
2970 if (presnap > start) {
2971 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2975 } else if (presnap < start) {
2976 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2982 /* handled at entry */
2990 Editor::setup_toolbar ()
2992 HBox* mode_box = manage(new HBox);
2993 mode_box->set_border_width (2);
2994 mode_box->set_spacing(2);
2996 HBox* mouse_mode_box = manage (new HBox);
2997 HBox* mouse_mode_hbox = manage (new HBox);
2998 VBox* mouse_mode_vbox = manage (new VBox);
2999 Alignment* mouse_mode_align = manage (new Alignment);
3001 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3002 mouse_mode_size_group->add_widget (smart_mode_button);
3003 mouse_mode_size_group->add_widget (mouse_move_button);
3004 mouse_mode_size_group->add_widget (mouse_cut_button);
3005 mouse_mode_size_group->add_widget (mouse_select_button);
3006 mouse_mode_size_group->add_widget (mouse_timefx_button);
3007 mouse_mode_size_group->add_widget (mouse_audition_button);
3008 mouse_mode_size_group->add_widget (mouse_draw_button);
3009 mouse_mode_size_group->add_widget (mouse_content_button);
3011 mouse_mode_size_group->add_widget (zoom_in_button);
3012 mouse_mode_size_group->add_widget (zoom_out_button);
3013 mouse_mode_size_group->add_widget (zoom_preset_selector);
3014 mouse_mode_size_group->add_widget (zoom_out_full_button);
3015 mouse_mode_size_group->add_widget (zoom_focus_selector);
3017 mouse_mode_size_group->add_widget (tav_shrink_button);
3018 mouse_mode_size_group->add_widget (tav_expand_button);
3019 mouse_mode_size_group->add_widget (visible_tracks_selector);
3021 mouse_mode_size_group->add_widget (snap_type_selector);
3022 mouse_mode_size_group->add_widget (snap_mode_selector);
3024 mouse_mode_size_group->add_widget (edit_point_selector);
3025 mouse_mode_size_group->add_widget (edit_mode_selector);
3027 mouse_mode_size_group->add_widget (*nudge_clock);
3028 mouse_mode_size_group->add_widget (nudge_forward_button);
3029 mouse_mode_size_group->add_widget (nudge_backward_button);
3031 mouse_mode_hbox->set_spacing (2);
3033 if (!ARDOUR::Profile->get_trx()) {
3034 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3037 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3038 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3040 if (!ARDOUR::Profile->get_mixbus()) {
3041 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3044 if (!ARDOUR::Profile->get_trx()) {
3045 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3046 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3047 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3048 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3051 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3053 mouse_mode_align->add (*mouse_mode_vbox);
3054 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3056 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3058 edit_mode_selector.set_name ("mouse mode button");
3060 if (!ARDOUR::Profile->get_trx()) {
3061 mode_box->pack_start (edit_mode_selector, false, false);
3064 mode_box->pack_start (*mouse_mode_box, false, false);
3068 _zoom_box.set_spacing (2);
3069 _zoom_box.set_border_width (2);
3073 zoom_preset_selector.set_name ("zoom button");
3074 zoom_preset_selector.set_image(::get_icon ("time_exp"));
3075 zoom_preset_selector.set_size_request (42, -1);
3077 zoom_in_button.set_name ("zoom button");
3078 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3079 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3080 zoom_in_button.set_related_action (act);
3082 zoom_out_button.set_name ("zoom button");
3083 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3084 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3085 zoom_out_button.set_related_action (act);
3087 zoom_out_full_button.set_name ("zoom button");
3088 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3089 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3090 zoom_out_full_button.set_related_action (act);
3092 zoom_focus_selector.set_name ("zoom button");
3094 if (ARDOUR::Profile->get_mixbus()) {
3095 _zoom_box.pack_start (zoom_preset_selector, false, false);
3096 } else if (ARDOUR::Profile->get_trx()) {
3097 mode_box->pack_start (zoom_out_button, false, false);
3098 mode_box->pack_start (zoom_in_button, false, false);
3100 _zoom_box.pack_start (zoom_out_button, false, false);
3101 _zoom_box.pack_start (zoom_in_button, false, false);
3102 _zoom_box.pack_start (zoom_out_full_button, false, false);
3103 _zoom_box.pack_start (zoom_focus_selector, false, false);
3106 /* Track zoom buttons */
3107 visible_tracks_selector.set_name ("zoom button");
3108 if (Profile->get_mixbus()) {
3109 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3110 visible_tracks_selector.set_size_request (42, -1);
3112 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3115 tav_expand_button.set_name ("zoom button");
3116 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3117 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3118 tav_expand_button.set_related_action (act);
3120 tav_shrink_button.set_name ("zoom button");
3121 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3122 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3123 tav_shrink_button.set_related_action (act);
3125 if (ARDOUR::Profile->get_mixbus()) {
3126 _zoom_box.pack_start (visible_tracks_selector);
3127 } else if (ARDOUR::Profile->get_trx()) {
3128 _zoom_box.pack_start (tav_shrink_button);
3129 _zoom_box.pack_start (tav_expand_button);
3131 _zoom_box.pack_start (visible_tracks_selector);
3132 _zoom_box.pack_start (tav_shrink_button);
3133 _zoom_box.pack_start (tav_expand_button);
3136 snap_box.set_spacing (2);
3137 snap_box.set_border_width (2);
3139 snap_type_selector.set_name ("mouse mode button");
3141 snap_mode_selector.set_name ("mouse mode button");
3143 edit_point_selector.set_name ("mouse mode button");
3145 snap_box.pack_start (snap_mode_selector, false, false);
3146 snap_box.pack_start (snap_type_selector, false, false);
3147 snap_box.pack_start (edit_point_selector, false, false);
3151 HBox *nudge_box = manage (new HBox);
3152 nudge_box->set_spacing (2);
3153 nudge_box->set_border_width (2);
3155 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3156 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3158 nudge_box->pack_start (nudge_backward_button, false, false);
3159 nudge_box->pack_start (nudge_forward_button, false, false);
3160 nudge_box->pack_start (*nudge_clock, false, false);
3163 /* Pack everything in... */
3165 HBox* hbox = manage (new HBox);
3166 hbox->set_spacing(2);
3168 toolbar_hbox.set_spacing (2);
3169 toolbar_hbox.set_border_width (1);
3171 toolbar_hbox.pack_start (*mode_box, false, false);
3172 if (!ARDOUR::Profile->get_trx()) {
3173 toolbar_hbox.pack_start (_zoom_box, false, false);
3174 toolbar_hbox.pack_start (*hbox, false, false);
3177 if (!ARDOUR::Profile->get_trx()) {
3178 hbox->pack_start (snap_box, false, false);
3179 hbox->pack_start (*nudge_box, false, false);
3184 toolbar_base.set_name ("ToolBarBase");
3185 toolbar_base.add (toolbar_hbox);
3187 _toolbar_viewport.add (toolbar_base);
3188 /* stick to the required height but allow width to vary if there's not enough room */
3189 _toolbar_viewport.set_size_request (1, -1);
3191 toolbar_frame.set_shadow_type (SHADOW_OUT);
3192 toolbar_frame.set_name ("BaseFrame");
3193 toolbar_frame.add (_toolbar_viewport);
3197 Editor::build_edit_point_menu ()
3199 using namespace Menu_Helpers;
3201 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3202 if(!Profile->get_mixbus())
3203 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3204 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3206 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3210 Editor::build_edit_mode_menu ()
3212 using namespace Menu_Helpers;
3214 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3215 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3216 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3217 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3219 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3223 Editor::build_snap_mode_menu ()
3225 using namespace Menu_Helpers;
3227 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3228 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3229 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3231 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3235 Editor::build_snap_type_menu ()
3237 using namespace Menu_Helpers;
3239 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3240 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3241 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3242 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3243 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3244 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3245 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3246 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3247 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3248 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3249 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3250 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3251 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3252 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3253 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3254 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3255 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3256 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3257 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3258 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3259 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3260 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3261 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3262 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3263 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3264 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3265 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3266 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3267 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3268 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3270 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3275 Editor::setup_tooltips ()
3277 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3278 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3279 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3280 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3281 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3282 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3283 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3284 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3285 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3286 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3287 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3288 set_tooltip (zoom_in_button, _("Zoom In"));
3289 set_tooltip (zoom_out_button, _("Zoom Out"));
3290 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3291 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3292 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3293 set_tooltip (tav_expand_button, _("Expand Tracks"));
3294 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3295 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3296 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3297 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3298 set_tooltip (edit_point_selector, _("Edit Point"));
3299 set_tooltip (edit_mode_selector, _("Edit Mode"));
3300 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3304 Editor::convert_drop_to_paths (
3305 vector<string>& paths,
3306 const RefPtr<Gdk::DragContext>& /*context*/,
3309 const SelectionData& data,
3313 if (_session == 0) {
3317 vector<string> uris = data.get_uris();
3321 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3322 are actually URI lists. So do it by hand.
3325 if (data.get_target() != "text/plain") {
3329 /* Parse the "uri-list" format that Nautilus provides,
3330 where each pathname is delimited by \r\n.
3332 THERE MAY BE NO NULL TERMINATING CHAR!!!
3335 string txt = data.get_text();
3339 p = (char *) malloc (txt.length() + 1);
3340 txt.copy (p, txt.length(), 0);
3341 p[txt.length()] = '\0';
3347 while (g_ascii_isspace (*p))
3351 while (*q && (*q != '\n') && (*q != '\r')) {
3358 while (q > p && g_ascii_isspace (*q))
3363 uris.push_back (string (p, q - p + 1));
3367 p = strchr (p, '\n');
3379 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3380 if ((*i).substr (0,7) == "file://") {
3381 paths.push_back (Glib::filename_from_uri (*i));
3389 Editor::new_tempo_section ()
3394 Editor::map_transport_state ()
3396 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3398 if (_session && _session->transport_stopped()) {
3399 have_pending_keyboard_selection = false;
3402 update_loop_range_view ();
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), false)));
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::pane_allocation_handler (Allocation &alloc, Paned* which)
3935 /* recover or initialize pane positions. do this here rather than earlier because
3936 we don't want the positions to change the child allocations, which they seem to do.
3938 See comments in mixer_ui.cc about how this works.
3943 XMLNode* geometry = ARDOUR_UI::instance()->editor_settings();
3952 if (which == static_cast<Paned*> (&edit_pane)) {
3954 if (done & Horizontal) {
3958 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3959 _notebook_shrunk = string_is_affirmative (prop->value ());
3962 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3963 /* initial allocation is 90% to canvas, 10% to notebook */
3964 pos = (int) floor (alloc.get_width() * 0.90f);
3966 pos = atof (prop->value());
3970 /* older versions of Ardour stored absolute position */
3971 if (alloc.get_width() > pos) {
3972 edit_pane.set_position (pos);
3973 done = (Pane) (done | Horizontal);
3976 if (alloc.get_width() > 1.0/pos) {
3977 paned_set_position_as_fraction (edit_pane, pos, false);
3978 done = (Pane) (done | Horizontal);
3982 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3984 if (done & Vertical) {
3988 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3989 /* initial allocation is 90% to canvas, 10% to summary */
3990 pos = (int) floor (alloc.get_height() * 0.90f);
3993 pos = atof (prop->value());
3997 /* older versions of Ardour stored absolute position */
3998 if (alloc.get_height() > pos) {
3999 editor_summary_pane.set_position (pos);
4000 done = (Pane) (done | Vertical);
4003 if (alloc.get_height() > 1.0/pos) {
4004 paned_set_position_as_fraction (editor_summary_pane, pos, true);
4005 done = (Pane) (done | Vertical);
4012 Editor::set_show_measures (bool yn)
4014 if (_show_measures != yn) {
4017 if ((_show_measures = yn) == true) {
4019 tempo_lines->show();
4022 std::vector<TempoMap::BBTPoint> grid;
4023 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
4024 draw_measures (grid);
4032 Editor::toggle_follow_playhead ()
4034 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
4036 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4037 set_follow_playhead (tact->get_active());
4041 /** @param yn true to follow playhead, otherwise false.
4042 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4045 Editor::set_follow_playhead (bool yn, bool catch_up)
4047 if (_follow_playhead != yn) {
4048 if ((_follow_playhead = yn) == true && catch_up) {
4050 reset_x_origin_to_follow_playhead ();
4057 Editor::toggle_stationary_playhead ()
4059 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4061 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4062 set_stationary_playhead (tact->get_active());
4067 Editor::set_stationary_playhead (bool yn)
4069 if (_stationary_playhead != yn) {
4070 if ((_stationary_playhead = yn) == true) {
4072 // FIXME need a 3.0 equivalent of this 2.X call
4073 // update_current_screen ();
4080 Editor::playlist_selector () const
4082 return *_playlist_selector;
4086 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4088 if (paste_count == 0) {
4089 /* don't bother calculating an offset that will be zero anyway */
4093 /* calculate basic unsnapped multi-paste offset */
4094 framecnt_t offset = paste_count * duration;
4096 /* snap offset so pos + offset is aligned to the grid */
4097 framepos_t offset_pos = pos + offset;
4098 snap_to(offset_pos, RoundUpMaybe);
4099 offset = offset_pos - pos;
4105 Editor::get_grid_beat_divisions(framepos_t position)
4107 switch (_snap_type) {
4108 case SnapToBeatDiv128: return 128;
4109 case SnapToBeatDiv64: return 64;
4110 case SnapToBeatDiv32: return 32;
4111 case SnapToBeatDiv28: return 28;
4112 case SnapToBeatDiv24: return 24;
4113 case SnapToBeatDiv20: return 20;
4114 case SnapToBeatDiv16: return 16;
4115 case SnapToBeatDiv14: return 14;
4116 case SnapToBeatDiv12: return 12;
4117 case SnapToBeatDiv10: return 10;
4118 case SnapToBeatDiv8: return 8;
4119 case SnapToBeatDiv7: return 7;
4120 case SnapToBeatDiv6: return 6;
4121 case SnapToBeatDiv5: return 5;
4122 case SnapToBeatDiv4: return 4;
4123 case SnapToBeatDiv3: return 3;
4124 case SnapToBeatDiv2: return 2;
4131 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4135 const unsigned divisions = get_grid_beat_divisions(position);
4137 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4140 switch (_snap_type) {
4142 return Evoral::Beats(1.0);
4145 return Evoral::Beats(_session->tempo_map().meter_at_frame (position).divisions_per_bar());
4153 return Evoral::Beats();
4157 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4161 ret = nudge_clock->current_duration (pos);
4162 next = ret + 1; /* XXXX fix me */
4168 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4170 ArdourDialog dialog (_("Playlist Deletion"));
4171 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4172 "If it is kept, its audio files will not be cleaned.\n"
4173 "If it is deleted, audio files used by it alone will be cleaned."),
4176 dialog.set_position (WIN_POS_CENTER);
4177 dialog.get_vbox()->pack_start (label);
4181 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4182 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4183 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4184 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4185 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4187 // by default gtk uses the left most button
4188 keep->grab_focus ();
4190 switch (dialog.run ()) {
4192 /* keep this and all remaining ones */
4197 /* delete this and all others */
4201 case RESPONSE_ACCEPT:
4202 /* delete the playlist */
4206 case RESPONSE_REJECT:
4207 /* keep the playlist */
4219 Editor::audio_region_selection_covers (framepos_t where)
4221 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4222 if ((*a)->region()->covers (where)) {
4231 Editor::prepare_for_cleanup ()
4233 cut_buffer->clear_regions ();
4234 cut_buffer->clear_playlists ();
4236 selection->clear_regions ();
4237 selection->clear_playlists ();
4239 _regions->suspend_redisplay ();
4243 Editor::finish_cleanup ()
4245 _regions->resume_redisplay ();
4249 Editor::transport_loop_location()
4252 return _session->locations()->auto_loop_location();
4259 Editor::transport_punch_location()
4262 return _session->locations()->auto_punch_location();
4269 Editor::control_layout_scroll (GdkEventScroll* ev)
4271 /* Just forward to the normal canvas scroll method. The coordinate
4272 systems are different but since the canvas is always larger than the
4273 track headers, and aligned with the trackview area, this will work.
4275 In the not too distant future this layout is going away anyway and
4276 headers will be on the canvas.
4278 return canvas_scroll_event (ev, false);
4282 Editor::session_state_saved (string)
4285 _snapshots->redisplay ();
4289 Editor::maximise_editing_space ()
4295 Gtk::Window* toplevel = current_toplevel();
4298 toplevel->fullscreen ();
4304 Editor::restore_editing_space ()
4310 Gtk::Window* toplevel = current_toplevel();
4313 toplevel->unfullscreen();
4319 * Make new playlists for a given track and also any others that belong
4320 * to the same active route group with the `select' property.
4325 Editor::new_playlists (TimeAxisView* v)
4327 begin_reversible_command (_("new playlists"));
4328 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4329 _session->playlists->get (playlists);
4330 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4331 commit_reversible_command ();
4335 * Use a copy of the current playlist for a given track and also any others that belong
4336 * to the same active route group with the `select' property.
4341 Editor::copy_playlists (TimeAxisView* v)
4343 begin_reversible_command (_("copy playlists"));
4344 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4345 _session->playlists->get (playlists);
4346 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4347 commit_reversible_command ();
4350 /** Clear the current playlist for a given track and also any others that belong
4351 * to the same active route group with the `select' property.
4356 Editor::clear_playlists (TimeAxisView* v)
4358 begin_reversible_command (_("clear playlists"));
4359 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4360 _session->playlists->get (playlists);
4361 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4362 commit_reversible_command ();
4366 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4368 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4372 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4374 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4378 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4380 atv.clear_playlist ();
4384 Editor::get_y_origin () const
4386 return vertical_adjustment.get_value ();
4389 /** Queue up a change to the viewport x origin.
4390 * @param frame New x origin.
4393 Editor::reset_x_origin (framepos_t frame)
4395 pending_visual_change.add (VisualChange::TimeOrigin);
4396 pending_visual_change.time_origin = frame;
4397 ensure_visual_change_idle_handler ();
4401 Editor::reset_y_origin (double y)
4403 pending_visual_change.add (VisualChange::YOrigin);
4404 pending_visual_change.y_origin = y;
4405 ensure_visual_change_idle_handler ();
4409 Editor::reset_zoom (framecnt_t spp)
4411 if (spp == samples_per_pixel) {
4415 pending_visual_change.add (VisualChange::ZoomLevel);
4416 pending_visual_change.samples_per_pixel = spp;
4417 ensure_visual_change_idle_handler ();
4421 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4423 reset_x_origin (frame);
4426 if (!no_save_visual) {
4427 undo_visual_stack.push_back (current_visual_state(false));
4431 Editor::VisualState::VisualState (bool with_tracks)
4432 : gui_state (with_tracks ? new GUIObjectState : 0)
4436 Editor::VisualState::~VisualState ()
4441 Editor::VisualState*
4442 Editor::current_visual_state (bool with_tracks)
4444 VisualState* vs = new VisualState (with_tracks);
4445 vs->y_position = vertical_adjustment.get_value();
4446 vs->samples_per_pixel = samples_per_pixel;
4447 vs->leftmost_frame = leftmost_frame;
4448 vs->zoom_focus = zoom_focus;
4451 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4458 Editor::undo_visual_state ()
4460 if (undo_visual_stack.empty()) {
4464 VisualState* vs = undo_visual_stack.back();
4465 undo_visual_stack.pop_back();
4468 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4471 use_visual_state (*vs);
4476 Editor::redo_visual_state ()
4478 if (redo_visual_stack.empty()) {
4482 VisualState* vs = redo_visual_stack.back();
4483 redo_visual_stack.pop_back();
4485 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4486 // why do we check here?
4487 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4490 use_visual_state (*vs);
4495 Editor::swap_visual_state ()
4497 if (undo_visual_stack.empty()) {
4498 redo_visual_state ();
4500 undo_visual_state ();
4505 Editor::use_visual_state (VisualState& vs)
4507 PBD::Unwinder<bool> nsv (no_save_visual, true);
4508 DisplaySuspender ds;
4510 vertical_adjustment.set_value (vs.y_position);
4512 set_zoom_focus (vs.zoom_focus);
4513 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4516 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4518 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4519 (*i)->clear_property_cache();
4520 (*i)->reset_visual_state ();
4524 _routes->update_visibility ();
4527 /** This is the core function that controls the zoom level of the canvas. It is called
4528 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4529 * @param spp new number of samples per pixel
4532 Editor::set_samples_per_pixel (framecnt_t spp)
4538 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4539 const framecnt_t lots_of_pixels = 4000;
4541 /* if the zoom level is greater than what you'd get trying to display 3
4542 * days of audio on a really big screen, then it's too big.
4545 if (spp * lots_of_pixels > three_days) {
4549 samples_per_pixel = spp;
4552 tempo_lines->tempo_map_changed();
4555 bool const showing_time_selection = selection->time.length() > 0;
4557 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4558 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4559 (*i)->reshow_selection (selection->time);
4563 ZoomChanged (); /* EMIT_SIGNAL */
4565 ArdourCanvas::GtkCanvasViewport* c;
4567 c = get_track_canvas();
4569 c->canvas()->zoomed ();
4572 if (playhead_cursor) {
4573 playhead_cursor->set_position (playhead_cursor->current_frame ());
4576 refresh_location_display();
4577 _summary->set_overlays_dirty ();
4579 update_marker_labels ();
4585 Editor::queue_visual_videotimeline_update ()
4588 * pending_visual_change.add (VisualChange::VideoTimeline);
4589 * or maybe even more specific: which videotimeline-image
4590 * currently it calls update_video_timeline() to update
4591 * _all outdated_ images on the video-timeline.
4592 * see 'exposeimg()' in video_image_frame.cc
4594 ensure_visual_change_idle_handler ();
4598 Editor::ensure_visual_change_idle_handler ()
4600 if (pending_visual_change.idle_handler_id < 0) {
4601 // see comment in add_to_idle_resize above.
4602 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4603 pending_visual_change.being_handled = false;
4608 Editor::_idle_visual_changer (void* arg)
4610 return static_cast<Editor*>(arg)->idle_visual_changer ();
4614 Editor::idle_visual_changer ()
4616 /* set_horizontal_position() below (and maybe other calls) call
4617 gtk_main_iteration(), so it's possible that a signal will be handled
4618 half-way through this method. If this signal wants an
4619 idle_visual_changer we must schedule another one after this one, so
4620 mark the idle_handler_id as -1 here to allow that. Also make a note
4621 that we are doing the visual change, so that changes in response to
4622 super-rapid-screen-update can be dropped if we are still processing
4626 pending_visual_change.idle_handler_id = -1;
4627 pending_visual_change.being_handled = true;
4629 VisualChange vc = pending_visual_change;
4631 pending_visual_change.pending = (VisualChange::Type) 0;
4633 visual_changer (vc);
4635 pending_visual_change.being_handled = false;
4637 return 0; /* this is always a one-shot call */
4641 Editor::visual_changer (const VisualChange& vc)
4643 double const last_time_origin = horizontal_position ();
4645 if (vc.pending & VisualChange::ZoomLevel) {
4646 set_samples_per_pixel (vc.samples_per_pixel);
4648 compute_fixed_ruler_scale ();
4650 std::vector<TempoMap::BBTPoint> grid;
4651 compute_current_bbt_points (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4652 compute_bbt_ruler_scale (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4653 update_tempo_based_rulers (grid);
4655 update_video_timeline();
4658 if (vc.pending & VisualChange::TimeOrigin) {
4659 set_horizontal_position (vc.time_origin / samples_per_pixel);
4662 if (vc.pending & VisualChange::YOrigin) {
4663 vertical_adjustment.set_value (vc.y_origin);
4666 if (last_time_origin == horizontal_position ()) {
4667 /* changed signal not emitted */
4668 update_fixed_rulers ();
4669 redisplay_tempo (true);
4672 if (!(vc.pending & VisualChange::ZoomLevel)) {
4673 update_video_timeline();
4676 _summary->set_overlays_dirty ();
4679 struct EditorOrderTimeAxisSorter {
4680 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4681 return a->order () < b->order ();
4686 Editor::sort_track_selection (TrackViewList& sel)
4688 EditorOrderTimeAxisSorter cmp;
4693 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4696 framepos_t where = 0;
4697 EditPoint ep = _edit_point;
4699 if (Profile->get_mixbus())
4700 if (ep == EditAtSelectedMarker)
4701 ep = EditAtPlayhead;
4703 if (from_outside_canvas && (ep == EditAtMouse)) {
4704 ep = EditAtPlayhead;
4705 } else if (from_context_menu && (ep == EditAtMouse)) {
4706 return canvas_event_sample (&context_click_event, 0, 0);
4709 if (entered_marker) {
4710 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4711 return entered_marker->position();
4714 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4715 ep = EditAtSelectedMarker;
4718 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4719 ep = EditAtPlayhead;
4723 case EditAtPlayhead:
4724 if (_dragging_playhead) {
4725 where = *_control_scroll_target;
4727 where = _session->audible_frame();
4729 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4732 case EditAtSelectedMarker:
4733 if (!selection->markers.empty()) {
4735 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4738 where = loc->start();
4742 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4750 if (!mouse_frame (where, ignored)) {
4751 /* XXX not right but what can we do ? */
4755 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4763 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4765 if (!_session) return;
4767 begin_reversible_command (cmd);
4771 if ((tll = transport_loop_location()) == 0) {
4772 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4773 XMLNode &before = _session->locations()->get_state();
4774 _session->locations()->add (loc, true);
4775 _session->set_auto_loop_location (loc);
4776 XMLNode &after = _session->locations()->get_state();
4777 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4779 XMLNode &before = tll->get_state();
4780 tll->set_hidden (false, this);
4781 tll->set (start, end);
4782 XMLNode &after = tll->get_state();
4783 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4786 commit_reversible_command ();
4790 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4792 if (!_session) return;
4794 begin_reversible_command (cmd);
4798 if ((tpl = transport_punch_location()) == 0) {
4799 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4800 XMLNode &before = _session->locations()->get_state();
4801 _session->locations()->add (loc, true);
4802 _session->set_auto_punch_location (loc);
4803 XMLNode &after = _session->locations()->get_state();
4804 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4806 XMLNode &before = tpl->get_state();
4807 tpl->set_hidden (false, this);
4808 tpl->set (start, end);
4809 XMLNode &after = tpl->get_state();
4810 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4813 commit_reversible_command ();
4816 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4817 * @param rs List to which found regions are added.
4818 * @param where Time to look at.
4819 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4822 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4824 const TrackViewList* tracks;
4827 tracks = &track_views;
4832 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4834 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4837 boost::shared_ptr<Track> tr;
4838 boost::shared_ptr<Playlist> pl;
4840 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4842 boost::shared_ptr<RegionList> regions = pl->regions_at (
4843 (framepos_t) floor ( (double) where * tr->speed()));
4845 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4846 RegionView* rv = rtv->view()->find_view (*i);
4857 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4859 const TrackViewList* tracks;
4862 tracks = &track_views;
4867 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4868 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4870 boost::shared_ptr<Track> tr;
4871 boost::shared_ptr<Playlist> pl;
4873 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4875 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4876 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4878 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4880 RegionView* rv = rtv->view()->find_view (*i);
4891 /** Get regions using the following method:
4893 * Make a region list using:
4894 * (a) any selected regions
4895 * (b) the intersection of any selected tracks and the edit point(*)
4896 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4898 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4900 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4904 Editor::get_regions_from_selection_and_edit_point ()
4906 RegionSelection regions;
4908 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4909 regions.add (entered_regionview);
4911 regions = selection->regions;
4914 if ( regions.empty() ) {
4915 TrackViewList tracks = selection->tracks;
4917 if (!tracks.empty()) {
4918 /* no region selected or entered, but some selected tracks:
4919 * act on all regions on the selected tracks at the edit point
4921 framepos_t const where = get_preferred_edit_position ();
4922 get_regions_at(regions, where, tracks);
4929 /** Get regions using the following method:
4931 * Make a region list using:
4932 * (a) any selected regions
4933 * (b) the intersection of any selected tracks and the edit point(*)
4934 * (c) if neither exists, then whatever region is under the mouse
4936 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4938 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4941 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4943 RegionSelection regions;
4945 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4946 regions.add (entered_regionview);
4948 regions = selection->regions;
4951 if ( regions.empty() ) {
4952 TrackViewList tracks = selection->tracks;
4954 if (!tracks.empty()) {
4955 /* no region selected or entered, but some selected tracks:
4956 * act on all regions on the selected tracks at the edit point
4958 get_regions_at(regions, pos, tracks);
4965 /** Start with regions that are selected, or the entered regionview if none are selected.
4966 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4967 * of the regions that we started with.
4971 Editor::get_regions_from_selection_and_entered () const
4973 RegionSelection regions = selection->regions;
4975 if (regions.empty() && entered_regionview) {
4976 regions.add (entered_regionview);
4983 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4985 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4986 RouteTimeAxisView* rtav;
4988 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4989 boost::shared_ptr<Playlist> pl;
4990 std::vector<boost::shared_ptr<Region> > results;
4991 boost::shared_ptr<Track> tr;
4993 if ((tr = rtav->track()) == 0) {
4998 if ((pl = (tr->playlist())) != 0) {
4999 boost::shared_ptr<Region> r = pl->region_by_id (id);
5001 RegionView* rv = rtav->view()->find_view (r);
5003 regions.push_back (rv);
5012 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5015 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5016 MidiTimeAxisView* mtav;
5018 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5020 mtav->get_per_region_note_selection (selection);
5027 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5029 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5031 RouteTimeAxisView* tatv;
5033 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5035 boost::shared_ptr<Playlist> pl;
5036 vector<boost::shared_ptr<Region> > results;
5038 boost::shared_ptr<Track> tr;
5040 if ((tr = tatv->track()) == 0) {
5045 if ((pl = (tr->playlist())) != 0) {
5046 if (src_comparison) {
5047 pl->get_source_equivalent_regions (region, results);
5049 pl->get_region_list_equivalent_regions (region, results);
5053 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5054 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5055 regions.push_back (marv);
5064 Editor::show_rhythm_ferret ()
5066 if (rhythm_ferret == 0) {
5067 rhythm_ferret = new RhythmFerret(*this);
5070 rhythm_ferret->set_session (_session);
5071 rhythm_ferret->show ();
5072 rhythm_ferret->present ();
5076 Editor::first_idle ()
5078 MessageDialog* dialog = 0;
5080 if (track_views.size() > 1) {
5081 Timers::TimerSuspender t;
5082 dialog = new MessageDialog (
5083 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5087 ARDOUR_UI::instance()->flush_pending ();
5090 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5094 // first idle adds route children (automation tracks), so we need to redisplay here
5095 _routes->redisplay ();
5099 if (_session->undo_depth() == 0) {
5100 undo_action->set_sensitive(false);
5102 redo_action->set_sensitive(false);
5103 begin_selection_op_history ();
5109 Editor::_idle_resize (gpointer arg)
5111 return ((Editor*)arg)->idle_resize ();
5115 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5117 if (resize_idle_id < 0) {
5118 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5119 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5120 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5122 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5123 _pending_resize_amount = 0;
5126 /* make a note of the smallest resulting height, so that we can clamp the
5127 lower limit at TimeAxisView::hSmall */
5129 int32_t min_resulting = INT32_MAX;
5131 _pending_resize_amount += h;
5132 _pending_resize_view = view;
5134 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5136 if (selection->tracks.contains (_pending_resize_view)) {
5137 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5138 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5142 if (min_resulting < 0) {
5147 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5148 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5152 /** Handle pending resizing of tracks */
5154 Editor::idle_resize ()
5156 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5158 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5159 selection->tracks.contains (_pending_resize_view)) {
5161 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5162 if (*i != _pending_resize_view) {
5163 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5168 _pending_resize_amount = 0;
5169 _group_tabs->set_dirty ();
5170 resize_idle_id = -1;
5178 ENSURE_GUI_THREAD (*this, &Editor::located);
5181 playhead_cursor->set_position (_session->audible_frame ());
5182 if (_follow_playhead && !_pending_initial_locate) {
5183 reset_x_origin_to_follow_playhead ();
5187 _pending_locate_request = false;
5188 _pending_initial_locate = false;
5192 Editor::region_view_added (RegionView * rv)
5194 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5195 if (rv->region ()->id () == (*pr)) {
5196 selection->add (rv);
5197 selection->regions.pending.erase (pr);
5202 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5204 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5205 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5206 if (rv->region()->id () == (*rnote).first) {
5207 mrv->select_notes ((*rnote).second);
5208 selection->pending_midi_note_selection.erase(rnote);
5214 _summary->set_background_dirty ();
5218 Editor::region_view_removed ()
5220 _summary->set_background_dirty ();
5224 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5226 TrackViewList::const_iterator j = track_views.begin ();
5227 while (j != track_views.end()) {
5228 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5229 if (rtv && rtv->route() == r) {
5240 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5244 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5245 TimeAxisView* tv = axis_view_from_route (*i);
5255 Editor::suspend_route_redisplay ()
5258 _routes->suspend_redisplay();
5263 Editor::resume_route_redisplay ()
5266 _routes->redisplay(); // queue redisplay
5267 _routes->resume_redisplay();
5272 Editor::add_vcas (VCAList& vcas)
5274 VCATimeAxisView* vtv;
5275 list<VCATimeAxisView*> new_views;
5277 for (VCAList::iterator v = vcas.begin(); v != vcas.end(); ++v) {
5278 vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5280 new_views.push_back (vtv);
5283 if (new_views.size() > 0) {
5284 _routes->vcas_added (new_views);
5289 Editor::add_routes (RouteList& routes)
5291 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5293 RouteTimeAxisView *rtv;
5294 list<RouteTimeAxisView*> new_views;
5295 TrackViewList new_selection;
5296 bool from_scratch = (track_views.size() == 0);
5298 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5299 boost::shared_ptr<Route> route = (*x);
5301 if (route->is_auditioner() || route->is_monitor()) {
5305 DataType dt = route->input()->default_type();
5307 if (dt == ARDOUR::DataType::AUDIO) {
5308 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5309 rtv->set_route (route);
5310 } else if (dt == ARDOUR::DataType::MIDI) {
5311 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5312 rtv->set_route (route);
5314 throw unknown_type();
5317 new_views.push_back (rtv);
5318 track_views.push_back (rtv);
5319 new_selection.push_back (rtv);
5321 rtv->effective_gain_display ();
5323 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5324 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5327 if (new_views.size() > 0) {
5328 _routes->routes_added (new_views);
5329 _summary->routes_added (new_views);
5332 if (!from_scratch) {
5333 selection->tracks.clear();
5334 selection->add (new_selection);
5335 begin_selection_op_history();
5338 if (show_editor_mixer_when_tracks_arrive) {
5339 show_editor_mixer (true);
5342 editor_list_button.set_sensitive (true);
5346 Editor::timeaxisview_deleted (TimeAxisView *tv)
5348 if (tv == entered_track) {
5352 if (_session && _session->deletion_in_progress()) {
5353 /* the situation is under control */
5357 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5359 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5361 _routes->route_removed (tv);
5363 TimeAxisView::Children c = tv->get_child_list ();
5364 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5365 if (entered_track == i->get()) {
5370 /* remove it from the list of track views */
5372 TrackViewList::iterator i;
5374 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5375 i = track_views.erase (i);
5378 /* update whatever the current mixer strip is displaying, if revelant */
5380 boost::shared_ptr<Route> route;
5383 route = rtav->route ();
5386 if (current_mixer_strip && current_mixer_strip->route() == route) {
5388 TimeAxisView* next_tv;
5390 if (track_views.empty()) {
5392 } else if (i == track_views.end()) {
5393 next_tv = track_views.front();
5400 set_selected_mixer_strip (*next_tv);
5402 /* make the editor mixer strip go away setting the
5403 * button to inactive (which also unticks the menu option)
5406 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5412 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5414 if (apply_to_selection) {
5415 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5417 TrackSelection::iterator j = i;
5420 hide_track_in_display (*i, false);
5425 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5427 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5428 // this will hide the mixer strip
5429 set_selected_mixer_strip (*tv);
5432 _routes->hide_track_in_display (*tv);
5437 Editor::sync_track_view_list_and_routes ()
5439 track_views = TrackViewList (_routes->views ());
5441 _summary->set_background_dirty();
5442 _group_tabs->set_dirty ();
5444 return false; // do not call again (until needed)
5448 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5450 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5455 /** Find a RouteTimeAxisView by the ID of its route */
5457 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5459 RouteTimeAxisView* v;
5461 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5462 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5463 if(v->route()->id() == id) {
5473 Editor::fit_route_group (RouteGroup *g)
5475 TrackViewList ts = axis_views_from_routes (g->route_list ());
5480 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5482 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5485 _session->cancel_audition ();
5489 if (_session->is_auditioning()) {
5490 _session->cancel_audition ();
5491 if (r == last_audition_region) {
5496 _session->audition_region (r);
5497 last_audition_region = r;
5502 Editor::hide_a_region (boost::shared_ptr<Region> r)
5504 r->set_hidden (true);
5508 Editor::show_a_region (boost::shared_ptr<Region> r)
5510 r->set_hidden (false);
5514 Editor::audition_region_from_region_list ()
5516 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5520 Editor::hide_region_from_region_list ()
5522 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5526 Editor::show_region_in_region_list ()
5528 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5532 Editor::step_edit_status_change (bool yn)
5535 start_step_editing ();
5537 stop_step_editing ();
5542 Editor::start_step_editing ()
5544 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5548 Editor::stop_step_editing ()
5550 step_edit_connection.disconnect ();
5554 Editor::check_step_edit ()
5556 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5557 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5559 mtv->check_step_edit ();
5563 return true; // do it again, till we stop
5567 Editor::scroll_press (Direction dir)
5569 ++_scroll_callbacks;
5571 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5572 /* delay the first auto-repeat */
5578 scroll_backward (1);
5586 scroll_up_one_track ();
5590 scroll_down_one_track ();
5594 /* do hacky auto-repeat */
5595 if (!_scroll_connection.connected ()) {
5597 _scroll_connection = Glib::signal_timeout().connect (
5598 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5601 _scroll_callbacks = 0;
5608 Editor::scroll_release ()
5610 _scroll_connection.disconnect ();
5613 /** Queue a change for the Editor viewport x origin to follow the playhead */
5615 Editor::reset_x_origin_to_follow_playhead ()
5617 framepos_t const frame = playhead_cursor->current_frame ();
5619 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5621 if (_session->transport_speed() < 0) {
5623 if (frame > (current_page_samples() / 2)) {
5624 center_screen (frame-(current_page_samples()/2));
5626 center_screen (current_page_samples()/2);
5633 if (frame < leftmost_frame) {
5635 if (_session->transport_rolling()) {
5636 /* rolling; end up with the playhead at the right of the page */
5637 l = frame - current_page_samples ();
5639 /* not rolling: end up with the playhead 1/4 of the way along the page */
5640 l = frame - current_page_samples() / 4;
5644 if (_session->transport_rolling()) {
5645 /* rolling: end up with the playhead on the left of the page */
5648 /* not rolling: end up with the playhead 3/4 of the way along the page */
5649 l = frame - 3 * current_page_samples() / 4;
5657 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5663 Editor::super_rapid_screen_update ()
5665 if (!_session || !_session->engine().running()) {
5669 /* METERING / MIXER STRIPS */
5671 /* update track meters, if required */
5672 if (contents().is_mapped() && meters_running) {
5673 RouteTimeAxisView* rtv;
5674 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5675 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5676 rtv->fast_update ();
5681 /* and any current mixer strip */
5682 if (current_mixer_strip) {
5683 current_mixer_strip->fast_update ();
5686 /* PLAYHEAD AND VIEWPORT */
5688 framepos_t const frame = _session->audible_frame();
5690 /* There are a few reasons why we might not update the playhead / viewport stuff:
5692 * 1. we don't update things when there's a pending locate request, otherwise
5693 * when the editor requests a locate there is a chance that this method
5694 * will move the playhead before the locate request is processed, causing
5696 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5697 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5700 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5702 last_update_frame = frame;
5704 if (!_dragging_playhead) {
5705 playhead_cursor->set_position (frame);
5708 if (!_stationary_playhead) {
5710 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5711 /* We only do this if we aren't already
5712 handling a visual change (ie if
5713 pending_visual_change.being_handled is
5714 false) so that these requests don't stack
5715 up there are too many of them to handle in
5718 reset_x_origin_to_follow_playhead ();
5723 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5724 framepos_t const frame = playhead_cursor->current_frame ();
5725 double target = ((double)frame - (double)current_page_samples()/2.0);
5726 if (target <= 0.0) {
5729 // compare to EditorCursor::set_position()
5730 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5731 double const new_pos = sample_to_pixel_unrounded (target);
5732 if (rint (new_pos) != rint (old_pos)) {
5733 reset_x_origin (pixel_to_sample (floor (new_pos)));
5744 Editor::session_going_away ()
5746 _have_idled = false;
5748 _session_connections.drop_connections ();
5750 super_rapid_screen_update_connection.disconnect ();
5752 selection->clear ();
5753 cut_buffer->clear ();
5755 clicked_regionview = 0;
5756 clicked_axisview = 0;
5757 clicked_routeview = 0;
5758 entered_regionview = 0;
5760 last_update_frame = 0;
5763 playhead_cursor->hide ();
5765 /* rip everything out of the list displays */
5769 _route_groups->clear ();
5771 /* do this first so that deleting a track doesn't reset cms to null
5772 and thus cause a leak.
5775 if (current_mixer_strip) {
5776 if (current_mixer_strip->get_parent() != 0) {
5777 global_hpacker.remove (*current_mixer_strip);
5779 delete current_mixer_strip;
5780 current_mixer_strip = 0;
5783 /* delete all trackviews */
5785 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5788 track_views.clear ();
5790 nudge_clock->set_session (0);
5792 editor_list_button.set_active(false);
5793 editor_list_button.set_sensitive(false);
5795 /* clear tempo/meter rulers */
5796 remove_metric_marks ();
5798 clear_marker_display ();
5800 stop_step_editing ();
5804 /* get rid of any existing editor mixer strip */
5806 WindowTitle title(Glib::get_application_name());
5807 title += _("Editor");
5809 own_window()->set_title (title.get_string());
5812 SessionHandlePtr::session_going_away ();
5816 Editor::trigger_script (int i)
5818 LuaInstance::instance()-> call_action (i);
5822 Editor::set_script_action_name (int i, const std::string& n)
5824 string const a = string_compose (X_("script-action-%1"), i + 1);
5825 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5828 act->set_label (string_compose (_("Unset #%1"), i + 1));
5829 act->set_tooltip (_("no action bound"));
5830 act->set_sensitive (false);
5833 act->set_tooltip (n);
5834 act->set_sensitive (true);
5836 KeyEditor::UpdateBindings ();
5840 Editor::show_editor_list (bool yn)
5843 _the_notebook.show ();
5845 _the_notebook.hide ();
5850 Editor::change_region_layering_order (bool from_context_menu)
5852 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5854 if (!clicked_routeview) {
5855 if (layering_order_editor) {
5856 layering_order_editor->hide ();
5861 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5867 boost::shared_ptr<Playlist> pl = track->playlist();
5873 if (layering_order_editor == 0) {
5874 layering_order_editor = new RegionLayeringOrderEditor (*this);
5877 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5878 layering_order_editor->maybe_present ();
5882 Editor::update_region_layering_order_editor ()
5884 if (layering_order_editor && layering_order_editor->is_visible ()) {
5885 change_region_layering_order (true);
5890 Editor::setup_fade_images ()
5892 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5893 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5894 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5895 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5896 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5898 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5899 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5900 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5901 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5902 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5904 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5905 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5906 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5907 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5908 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5910 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5911 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5912 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5913 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5914 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5918 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5920 Editor::action_menu_item (std::string const & name)
5922 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5925 return *manage (a->create_menu_item ());
5929 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5931 EventBox* b = manage (new EventBox);
5932 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5933 Label* l = manage (new Label (name));
5937 _the_notebook.append_page (widget, *b);
5941 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5943 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5944 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5947 if (ev->type == GDK_2BUTTON_PRESS) {
5949 /* double-click on a notebook tab shrinks or expands the notebook */
5951 if (_notebook_shrunk) {
5952 if (pre_notebook_shrink_pane_width) {
5953 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5955 _notebook_shrunk = false;
5957 pre_notebook_shrink_pane_width = edit_pane.get_position();
5959 /* this expands the LHS of the edit pane to cover the notebook
5960 PAGE but leaves the tabs visible.
5962 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5963 _notebook_shrunk = true;
5971 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5973 using namespace Menu_Helpers;
5975 MenuList& items = _control_point_context_menu.items ();
5978 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5979 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5980 if (!can_remove_control_point (item)) {
5981 items.back().set_sensitive (false);
5984 _control_point_context_menu.popup (event->button.button, event->button.time);
5988 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5990 using namespace Menu_Helpers;
5992 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5997 /* We need to get the selection here and pass it to the operations, since
5998 popping up the menu will cause a region leave event which clears
5999 entered_regionview. */
6001 MidiRegionView& mrv = note->region_view();
6002 const RegionSelection rs = get_regions_from_selection_and_entered ();
6003 const uint32_t sel_size = mrv.selection_size ();
6005 MenuList& items = _note_context_menu.items();
6009 items.push_back(MenuElem(_("Delete"),
6010 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6013 items.push_back(MenuElem(_("Edit..."),
6014 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6015 if (sel_size != 1) {
6016 items.back().set_sensitive (false);
6019 items.push_back(MenuElem(_("Transpose..."),
6020 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6023 items.push_back(MenuElem(_("Legatize"),
6024 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6026 items.back().set_sensitive (false);
6029 items.push_back(MenuElem(_("Quantize..."),
6030 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6032 items.push_back(MenuElem(_("Remove Overlap"),
6033 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6035 items.back().set_sensitive (false);
6038 items.push_back(MenuElem(_("Transform..."),
6039 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6041 _note_context_menu.popup (event->button.button, event->button.time);
6045 Editor::zoom_vertical_modifier_released()
6047 _stepping_axis_view = 0;
6051 Editor::ui_parameter_changed (string parameter)
6053 if (parameter == "icon-set") {
6054 while (!_cursor_stack.empty()) {
6055 _cursor_stack.pop_back();
6057 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6058 _cursor_stack.push_back(_cursors->grabber);
6059 } else if (parameter == "draggable-playhead") {
6060 if (_verbose_cursor) {
6061 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6067 Editor::use_own_window (bool and_fill_it)
6069 bool new_window = !own_window();
6071 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6073 if (win && new_window) {
6074 win->set_name ("EditorWindow");
6076 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6078 // win->signal_realize().connect (*this, &Editor::on_realize);
6079 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6080 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6081 win->set_data ("ardour-bindings", bindings);
6086 DisplaySuspender ds;
6087 contents().show_all ();
6089 /* XXX: this is a bit unfortunate; it would probably
6090 be nicer if we could just call show () above rather
6091 than needing the show_all ()
6094 /* re-hide stuff if necessary */
6095 editor_list_button_toggled ();
6096 parameter_changed ("show-summary");
6097 parameter_changed ("show-group-tabs");
6098 parameter_changed ("show-zoom-tools");
6100 /* now reset all audio_time_axis heights, because widgets might need
6106 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6107 tv = (static_cast<TimeAxisView*>(*i));
6108 tv->reset_height ();
6111 if (current_mixer_strip) {
6112 current_mixer_strip->hide_things ();
6113 current_mixer_strip->parameter_changed ("mixer-element-visibility");