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.h"
76 #include "ardour/route_group.h"
77 #include "ardour/session_playlists.h"
78 #include "ardour/tempo.h"
79 #include "ardour/utils.h"
80 #include "ardour/vca_manager.h"
81 #include "ardour/vca.h"
83 #include "canvas/debug.h"
84 #include "canvas/text.h"
86 #include "control_protocol/control_protocol.h"
89 #include "analysis_window.h"
90 #include "ardour_spacer.h"
91 #include "audio_clock.h"
92 #include "audio_region_view.h"
93 #include "audio_streamview.h"
94 #include "audio_time_axis.h"
95 #include "automation_time_axis.h"
96 #include "bundle_manager.h"
97 #include "crossfade_edit.h"
101 #include "editor_cursors.h"
102 #include "editor_drag.h"
103 #include "editor_group_tabs.h"
104 #include "editor_locations.h"
105 #include "editor_regions.h"
106 #include "editor_route_groups.h"
107 #include "editor_routes.h"
108 #include "editor_snapshots.h"
109 #include "editor_summary.h"
110 #include "export_report.h"
111 #include "global_port_matrix.h"
112 #include "gui_object.h"
113 #include "gui_thread.h"
114 #include "keyboard.h"
115 #include "keyeditor.h"
116 #include "luainstance.h"
118 #include "midi_region_view.h"
119 #include "midi_time_axis.h"
120 #include "mixer_strip.h"
121 #include "mixer_ui.h"
122 #include "mouse_cursors.h"
123 #include "note_base.h"
124 #include "playlist_selector.h"
125 #include "public_editor.h"
126 #include "quantize_dialog.h"
127 #include "region_layering_order_editor.h"
128 #include "rgb_macros.h"
129 #include "rhythm_ferret.h"
130 #include "route_sorter.h"
131 #include "selection.h"
132 #include "simple_progress_dialog.h"
134 #include "tempo_lines.h"
135 #include "time_axis_view.h"
136 #include "time_info_box.h"
138 #include "tooltips.h"
139 #include "ui_config.h"
141 #include "vca_time_axis.h"
142 #include "verbose_cursor.h"
144 #include "pbd/i18n.h"
147 using namespace ARDOUR;
148 using namespace ARDOUR_UI_UTILS;
151 using namespace Glib;
152 using namespace Gtkmm2ext;
153 using namespace Editing;
155 using PBD::internationalize;
157 using Gtkmm2ext::Keyboard;
159 double Editor::timebar_height = 15.0;
161 static const gchar *_snap_type_strings[] = {
195 static const gchar *_snap_mode_strings[] = {
202 static const gchar *_edit_point_strings[] = {
209 static const gchar *_edit_mode_strings[] = {
217 static const gchar *_zoom_focus_strings[] = {
227 #ifdef USE_RUBBERBAND
228 static const gchar *_rb_opt_strings[] = {
231 N_("Balanced multitimbral mixture"),
232 N_("Unpitched percussion with stable notes"),
233 N_("Crisp monophonic instrumental"),
234 N_("Unpitched solo percussion"),
235 N_("Resample without preserving pitch"),
240 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
243 : PublicEditor (global_hpacker)
244 , editor_mixer_strip_width (Wide)
245 , constructed (false)
246 , _playlist_selector (0)
248 , no_save_visual (false)
250 , samples_per_pixel (2048)
251 , zoom_focus (ZoomFocusPlayhead)
252 , mouse_mode (MouseObject)
253 , pre_internal_snap_type (SnapToBeat)
254 , pre_internal_snap_mode (SnapOff)
255 , internal_snap_type (SnapToBeat)
256 , internal_snap_mode (SnapOff)
257 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
258 , _notebook_shrunk (false)
259 , location_marker_color (0)
260 , location_range_color (0)
261 , location_loop_color (0)
262 , location_punch_color (0)
263 , location_cd_marker_color (0)
265 , _show_marker_lines (false)
266 , clicked_axisview (0)
267 , clicked_routeview (0)
268 , clicked_regionview (0)
269 , clicked_selection (0)
270 , clicked_control_point (0)
271 , button_release_can_deselect (true)
272 , _mouse_changed_selection (false)
273 , region_edit_menu_split_item (0)
274 , region_edit_menu_split_multichannel_item (0)
275 , track_region_edit_playlist_menu (0)
276 , track_edit_playlist_submenu (0)
277 , track_selection_edit_playlist_submenu (0)
278 , _popup_region_menu_item (0)
280 , _track_canvas_viewport (0)
281 , within_track_canvas (false)
282 , _verbose_cursor (0)
286 , range_marker_group (0)
287 , transport_marker_group (0)
288 , cd_marker_group (0)
289 , _time_markers_group (0)
290 , hv_scroll_group (0)
292 , cursor_scroll_group (0)
293 , no_scroll_group (0)
294 , _trackview_group (0)
295 , _drag_motion_group (0)
296 , _canvas_drop_zone (0)
297 , no_ruler_shown_update (false)
298 , ruler_grabbed_widget (0)
300 , minsec_mark_interval (0)
301 , minsec_mark_modulo (0)
303 , timecode_mark_modulo (0)
304 , timecode_nmarks (0)
305 , _samples_ruler_interval (0)
308 , bbt_bar_helper_on (0)
309 , bbt_accent_modulo (0)
314 , visible_timebars (0)
315 , editor_ruler_menu (0)
319 , range_marker_bar (0)
320 , transport_marker_bar (0)
322 , minsec_label (_("Mins:Secs"))
323 , bbt_label (_("Bars:Beats"))
324 , timecode_label (_("Timecode"))
325 , samples_label (_("Samples"))
326 , tempo_label (_("Tempo"))
327 , meter_label (_("Meter"))
328 , mark_label (_("Location Markers"))
329 , range_mark_label (_("Range Markers"))
330 , transport_mark_label (_("Loop/Punch Ranges"))
331 , cd_mark_label (_("CD Markers"))
332 , videotl_label (_("Video Timeline"))
334 , playhead_cursor (0)
335 , edit_packer (4, 4, true)
336 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
337 , horizontal_adjustment (0.0, 0.0, 1e16)
338 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
339 , controls_layout (unused_adjustment, vertical_adjustment)
340 , _scroll_callbacks (0)
341 , _visible_canvas_width (0)
342 , _visible_canvas_height (0)
343 , _full_canvas_height (0)
344 , edit_controls_left_menu (0)
345 , edit_controls_right_menu (0)
346 , last_update_frame (0)
347 , cut_buffer_start (0)
348 , cut_buffer_length (0)
349 , button_bindings (0)
353 , current_interthread_info (0)
354 , analysis_window (0)
355 , select_new_marker (false)
357 , scrubbing_direction (0)
358 , scrub_reversals (0)
359 , scrub_reverse_distance (0)
360 , have_pending_keyboard_selection (false)
361 , pending_keyboard_selection_start (0)
362 , _snap_type (SnapToBeat)
363 , _snap_mode (SnapOff)
364 , snap_threshold (5.0)
365 , ignore_gui_changes (false)
366 , _drags (new DragManager (this))
368 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
369 , _dragging_playhead (false)
370 , _dragging_edit_point (false)
371 , _show_measures (true)
372 , _follow_playhead (true)
373 , _stationary_playhead (false)
376 , global_rect_group (0)
377 , time_line_group (0)
378 , tempo_marker_menu (0)
379 , meter_marker_menu (0)
381 , range_marker_menu (0)
382 , transport_marker_menu (0)
383 , new_transport_marker_menu (0)
385 , marker_menu_item (0)
386 , bbt_beat_subdivision (4)
387 , _visible_track_count (-1)
388 , toolbar_selection_clock_table (2,3)
389 , automation_mode_button (_("mode"))
390 , selection (new Selection (this))
391 , cut_buffer (new Selection (this))
392 , _selection_memento (new SelectionMemento())
393 , _all_region_actions_sensitized (false)
394 , _ignore_region_action (false)
395 , _last_region_menu_was_main (false)
396 , cd_marker_bar_drag_rect (0)
397 , range_bar_drag_rect (0)
398 , transport_bar_drag_rect (0)
399 , transport_bar_range_rect (0)
400 , transport_bar_preroll_rect (0)
401 , transport_bar_postroll_rect (0)
402 , transport_loop_range_rect (0)
403 , transport_punch_range_rect (0)
404 , transport_punchin_line (0)
405 , transport_punchout_line (0)
406 , transport_preroll_rect (0)
407 , transport_postroll_rect (0)
409 , rubberband_rect (0)
415 , autoscroll_horizontal_allowed (false)
416 , autoscroll_vertical_allowed (false)
418 , autoscroll_widget (0)
419 , show_gain_after_trim (false)
420 , selection_op_cmd_depth (0)
421 , selection_op_history_it (0)
422 , no_save_instant (false)
424 , current_mixer_strip (0)
425 , show_editor_mixer_when_tracks_arrive (false)
426 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
427 , current_stepping_trackview (0)
428 , last_track_height_step_timestamp (0)
430 , entered_regionview (0)
431 , clear_entered_track (false)
432 , _edit_point (EditAtMouse)
433 , meters_running (false)
435 , _have_idled (false)
436 , resize_idle_id (-1)
437 , _pending_resize_amount (0)
438 , _pending_resize_view (0)
439 , _pending_locate_request (false)
440 , _pending_initial_locate (false)
444 , layering_order_editor (0)
445 , _last_cut_copy_source_track (0)
446 , _region_selection_change_updates_region_list (true)
448 , _following_mixer_selection (false)
449 , _control_point_toggled_on_press (false)
450 , _stepping_axis_view (0)
451 , quantize_dialog (0)
452 , _main_menu_disabler (0)
453 , myactions (X_("editor"))
455 /* we are a singleton */
457 PublicEditor::_instance = this;
461 last_event_time.tv_sec = 0;
462 last_event_time.tv_usec = 0;
464 selection_op_history.clear();
467 snap_type_strings = I18N (_snap_type_strings);
468 snap_mode_strings = I18N (_snap_mode_strings);
469 zoom_focus_strings = I18N (_zoom_focus_strings);
470 edit_mode_strings = I18N (_edit_mode_strings);
471 edit_point_strings = I18N (_edit_point_strings);
472 #ifdef USE_RUBBERBAND
473 rb_opt_strings = I18N (_rb_opt_strings);
477 build_edit_mode_menu();
478 build_zoom_focus_menu();
479 build_track_count_menu();
480 build_snap_mode_menu();
481 build_snap_type_menu();
482 build_edit_point_menu();
484 location_marker_color = UIConfiguration::instance().color ("location marker");
485 location_range_color = UIConfiguration::instance().color ("location range");
486 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
487 location_loop_color = UIConfiguration::instance().color ("location loop");
488 location_punch_color = UIConfiguration::instance().color ("location punch");
490 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
492 TimeAxisView::setup_sizes ();
493 ArdourMarker::setup_sizes (timebar_height);
494 TempoCurve::setup_sizes (timebar_height);
496 bbt_label.set_name ("EditorRulerLabel");
497 bbt_label.set_size_request (-1, (int)timebar_height);
498 bbt_label.set_alignment (1.0, 0.5);
499 bbt_label.set_padding (5,0);
501 bbt_label.set_no_show_all();
502 minsec_label.set_name ("EditorRulerLabel");
503 minsec_label.set_size_request (-1, (int)timebar_height);
504 minsec_label.set_alignment (1.0, 0.5);
505 minsec_label.set_padding (5,0);
506 minsec_label.hide ();
507 minsec_label.set_no_show_all();
508 timecode_label.set_name ("EditorRulerLabel");
509 timecode_label.set_size_request (-1, (int)timebar_height);
510 timecode_label.set_alignment (1.0, 0.5);
511 timecode_label.set_padding (5,0);
512 timecode_label.hide ();
513 timecode_label.set_no_show_all();
514 samples_label.set_name ("EditorRulerLabel");
515 samples_label.set_size_request (-1, (int)timebar_height);
516 samples_label.set_alignment (1.0, 0.5);
517 samples_label.set_padding (5,0);
518 samples_label.hide ();
519 samples_label.set_no_show_all();
521 tempo_label.set_name ("EditorRulerLabel");
522 tempo_label.set_size_request (-1, (int)timebar_height);
523 tempo_label.set_alignment (1.0, 0.5);
524 tempo_label.set_padding (5,0);
526 tempo_label.set_no_show_all();
528 meter_label.set_name ("EditorRulerLabel");
529 meter_label.set_size_request (-1, (int)timebar_height);
530 meter_label.set_alignment (1.0, 0.5);
531 meter_label.set_padding (5,0);
533 meter_label.set_no_show_all();
535 if (Profile->get_trx()) {
536 mark_label.set_text (_("Markers"));
538 mark_label.set_name ("EditorRulerLabel");
539 mark_label.set_size_request (-1, (int)timebar_height);
540 mark_label.set_alignment (1.0, 0.5);
541 mark_label.set_padding (5,0);
543 mark_label.set_no_show_all();
545 cd_mark_label.set_name ("EditorRulerLabel");
546 cd_mark_label.set_size_request (-1, (int)timebar_height);
547 cd_mark_label.set_alignment (1.0, 0.5);
548 cd_mark_label.set_padding (5,0);
549 cd_mark_label.hide();
550 cd_mark_label.set_no_show_all();
552 videotl_bar_height = 4;
553 videotl_label.set_name ("EditorRulerLabel");
554 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
555 videotl_label.set_alignment (1.0, 0.5);
556 videotl_label.set_padding (5,0);
557 videotl_label.hide();
558 videotl_label.set_no_show_all();
560 range_mark_label.set_name ("EditorRulerLabel");
561 range_mark_label.set_size_request (-1, (int)timebar_height);
562 range_mark_label.set_alignment (1.0, 0.5);
563 range_mark_label.set_padding (5,0);
564 range_mark_label.hide();
565 range_mark_label.set_no_show_all();
567 transport_mark_label.set_name ("EditorRulerLabel");
568 transport_mark_label.set_size_request (-1, (int)timebar_height);
569 transport_mark_label.set_alignment (1.0, 0.5);
570 transport_mark_label.set_padding (5,0);
571 transport_mark_label.hide();
572 transport_mark_label.set_no_show_all();
574 initialize_canvas ();
576 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
578 _summary = new EditorSummary (this);
580 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
581 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
583 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
585 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
586 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
588 edit_controls_vbox.set_spacing (0);
589 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
590 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
592 HBox* h = manage (new HBox);
593 _group_tabs = new EditorGroupTabs (this);
594 if (!ARDOUR::Profile->get_trx()) {
595 h->pack_start (*_group_tabs, PACK_SHRINK);
597 h->pack_start (edit_controls_vbox);
598 controls_layout.add (*h);
600 controls_layout.set_name ("EditControlsBase");
601 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
602 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
603 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
605 _cursors = new MouseCursors;
606 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
607 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
609 /* Push default cursor to ever-present bottom of cursor stack. */
610 push_canvas_cursor(_cursors->grabber);
612 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
614 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
615 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
616 pad_line_1->set_outline_color (0xFF0000FF);
622 edit_packer.set_col_spacings (0);
623 edit_packer.set_row_spacings (0);
624 edit_packer.set_homogeneous (false);
625 edit_packer.set_border_width (0);
626 edit_packer.set_name ("EditorWindow");
628 time_bars_event_box.add (time_bars_vbox);
629 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
630 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
632 /* labels for the time bars */
633 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
635 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
637 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
639 bottom_hbox.set_border_width (2);
640 bottom_hbox.set_spacing (3);
642 _route_groups = new EditorRouteGroups (this);
643 _routes = new EditorRoutes (this);
644 _regions = new EditorRegions (this);
645 _snapshots = new EditorSnapshots (this);
646 _locations = new EditorLocations (this);
647 _time_info_box = new TimeInfoBox (true);
649 /* these are static location signals */
651 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
652 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
653 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
655 add_notebook_page (_("Regions"), _regions->widget ());
656 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
657 add_notebook_page (_("Snapshots"), _snapshots->widget ());
658 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
659 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
661 _the_notebook.set_show_tabs (true);
662 _the_notebook.set_scrollable (true);
663 _the_notebook.popup_disable ();
664 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
665 _the_notebook.show_all ();
667 _notebook_shrunk = false;
670 /* Pick up some settings we need to cache, early */
672 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
675 if (settings && (prop = settings->property ("notebook-shrunk"))) {
676 _notebook_shrunk = string_is_affirmative (prop->value ());
679 editor_summary_pane.set_check_divider_position (true);
680 editor_summary_pane.add (edit_packer);
682 Button* summary_arrows_left_left = manage (new Button);
683 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
684 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
685 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
687 Button* summary_arrows_left_right = manage (new Button);
688 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
689 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
690 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
692 VBox* summary_arrows_left = manage (new VBox);
693 summary_arrows_left->pack_start (*summary_arrows_left_left);
694 summary_arrows_left->pack_start (*summary_arrows_left_right);
696 Button* summary_arrows_right_up = manage (new Button);
697 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
698 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
699 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
701 Button* summary_arrows_right_down = manage (new Button);
702 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
703 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
704 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
706 VBox* summary_arrows_right = manage (new VBox);
707 summary_arrows_right->pack_start (*summary_arrows_right_up);
708 summary_arrows_right->pack_start (*summary_arrows_right_down);
710 Frame* summary_frame = manage (new Frame);
711 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
713 summary_frame->add (*_summary);
714 summary_frame->show ();
716 _summary_hbox.pack_start (*summary_arrows_left, false, false);
717 _summary_hbox.pack_start (*summary_frame, true, true);
718 _summary_hbox.pack_start (*summary_arrows_right, false, false);
720 if (!ARDOUR::Profile->get_trx()) {
721 editor_summary_pane.add (_summary_hbox);
724 edit_pane.set_check_divider_position (true);
725 edit_pane.add (editor_summary_pane);
726 if (!ARDOUR::Profile->get_trx()) {
727 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
728 _editor_list_vbox.pack_start (_the_notebook);
729 edit_pane.add (_editor_list_vbox);
730 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
733 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
734 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
741 if (!settings || ((prop = settings->property ("edit-horizontal-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
742 /* initial allocation is 90% to canvas, 10% to notebook */
743 edit_pane.set_divider (0, 0.90);
745 edit_pane.set_divider (0, fract);
748 if (!settings || ((prop = settings->property ("edit-vertical-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
749 /* initial allocation is 90% to canvas, 10% to summary */
750 editor_summary_pane.set_divider (0, 0.90);
753 editor_summary_pane.set_divider (0, fract);
757 global_vpacker.set_spacing (2);
758 global_vpacker.set_border_width (0);
760 //the next three EventBoxes provide the ability for their child widgets to have a background color. That is all.
762 Gtk::EventBox* ebox = manage (new Gtk::EventBox); //a themeable box
763 ebox->set_name("EditorWindow");
764 ebox->add (toolbar_hbox);
766 Gtk::EventBox* epane_box = manage (new Gtk::EventBox); //a themeable box
767 epane_box->set_name("EditorWindow");
768 epane_box->add (edit_pane);
770 Gtk::EventBox* epane_box2 = manage (new Gtk::EventBox); //a themeable box
771 epane_box2->set_name("EditorWindow");
772 epane_box2->add (global_vpacker);
774 global_vpacker.pack_start (*ebox, false, false);
775 global_vpacker.pack_start (*epane_box, true, true);
776 global_hpacker.pack_start (*epane_box2, true, true);
778 /* need to show the "contents" widget so that notebook will show if tab is switched to
781 global_hpacker.show ();
783 /* register actions now so that set_state() can find them and set toggles/checks etc */
790 _playlist_selector = new PlaylistSelector();
791 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
793 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
797 nudge_forward_button.set_name ("nudge button");
798 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
800 nudge_backward_button.set_name ("nudge button");
801 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
803 fade_context_menu.set_name ("ArdourContextMenu");
805 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
807 /* allow external control surfaces/protocols to do various things */
809 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
810 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
811 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
812 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
813 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
814 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
815 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
816 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
817 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
818 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
819 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
820 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
821 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
822 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
824 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
825 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
826 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
827 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
828 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
830 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
834 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
836 /* problematic: has to return a value and thus cannot be x-thread */
838 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
840 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
841 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
843 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
845 _ignore_region_action = false;
846 _last_region_menu_was_main = false;
847 _popup_region_menu_item = 0;
849 _show_marker_lines = false;
851 /* Button bindings */
853 button_bindings = new Bindings ("editor-mouse");
855 XMLNode* node = button_settings();
857 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
858 button_bindings->load_operation (**i);
864 /* grab current parameter state */
865 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
866 UIConfiguration::instance().map_parameters (pc);
868 setup_fade_images ();
870 LuaInstance::instance(); // instantiate
871 LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &Editor::set_script_action_name));
878 delete button_bindings;
880 delete _route_groups;
881 delete _track_canvas_viewport;
884 delete _verbose_cursor;
885 delete quantize_dialog;
891 delete _playlist_selector;
892 delete _time_info_box;
897 LuaInstance::destroy_instance ();
899 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
902 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_in_images.begin(); i != _xfade_in_images.end (); ++i) {
905 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_out_images.begin(); i != _xfade_out_images.end (); ++i) {
911 Editor::button_settings () const
913 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
914 XMLNode* node = find_named_node (*settings, X_("Buttons"));
917 node = new XMLNode (X_("Buttons"));
924 Editor::get_smart_mode () const
926 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
930 Editor::catch_vanishing_regionview (RegionView *rv)
932 /* note: the selection will take care of the vanishing
933 audioregionview by itself.
936 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
940 if (clicked_regionview == rv) {
941 clicked_regionview = 0;
944 if (entered_regionview == rv) {
945 set_entered_regionview (0);
948 if (!_all_region_actions_sensitized) {
949 sensitize_all_region_actions (true);
954 Editor::set_entered_regionview (RegionView* rv)
956 if (rv == entered_regionview) {
960 if (entered_regionview) {
961 entered_regionview->exited ();
964 entered_regionview = rv;
966 if (entered_regionview != 0) {
967 entered_regionview->entered ();
970 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
971 /* This RegionView entry might have changed what region actions
972 are allowed, so sensitize them all in case a key is pressed.
974 sensitize_all_region_actions (true);
979 Editor::set_entered_track (TimeAxisView* tav)
982 entered_track->exited ();
988 entered_track->entered ();
993 Editor::instant_save ()
995 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
1000 _session->add_instant_xml(get_state());
1002 Config->add_instant_xml(get_state());
1007 Editor::control_vertical_zoom_in_all ()
1009 tav_zoom_smooth (false, true);
1013 Editor::control_vertical_zoom_out_all ()
1015 tav_zoom_smooth (true, true);
1019 Editor::control_vertical_zoom_in_selected ()
1021 tav_zoom_smooth (false, false);
1025 Editor::control_vertical_zoom_out_selected ()
1027 tav_zoom_smooth (true, false);
1031 Editor::control_view (uint32_t view)
1033 goto_visual_state (view);
1037 Editor::control_unselect ()
1039 selection->clear_tracks ();
1043 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1045 TimeAxisView* tav = axis_view_from_stripable (s);
1049 case Selection::Add:
1050 selection->add (tav);
1052 case Selection::Toggle:
1053 selection->toggle (tav);
1055 case Selection::Extend:
1057 case Selection::Set:
1058 selection->set (tav);
1062 selection->clear_tracks ();
1067 Editor::control_step_tracks_up ()
1069 scroll_tracks_up_line ();
1073 Editor::control_step_tracks_down ()
1075 scroll_tracks_down_line ();
1079 Editor::control_scroll (float fraction)
1081 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1087 double step = fraction * current_page_samples();
1090 _control_scroll_target is an optional<T>
1092 it acts like a pointer to an framepos_t, with
1093 a operator conversion to boolean to check
1094 that it has a value could possibly use
1095 playhead_cursor->current_frame to store the
1096 value and a boolean in the class to know
1097 when it's out of date
1100 if (!_control_scroll_target) {
1101 _control_scroll_target = _session->transport_frame();
1102 _dragging_playhead = true;
1105 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1106 *_control_scroll_target = 0;
1107 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1108 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1110 *_control_scroll_target += (framepos_t) trunc (step);
1113 /* move visuals, we'll catch up with it later */
1115 playhead_cursor->set_position (*_control_scroll_target);
1116 UpdateAllTransportClocks (*_control_scroll_target);
1118 if (*_control_scroll_target > (current_page_samples() / 2)) {
1119 /* try to center PH in window */
1120 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1126 Now we do a timeout to actually bring the session to the right place
1127 according to the playhead. This is to avoid reading disk buffers on every
1128 call to control_scroll, which is driven by ScrollTimeline and therefore
1129 probably by a control surface wheel which can generate lots of events.
1131 /* cancel the existing timeout */
1133 control_scroll_connection.disconnect ();
1135 /* add the next timeout */
1137 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1141 Editor::deferred_control_scroll (framepos_t /*target*/)
1143 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1144 // reset for next stream
1145 _control_scroll_target = boost::none;
1146 _dragging_playhead = false;
1151 Editor::access_action (std::string action_group, std::string action_item)
1157 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1160 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1168 Editor::on_realize ()
1172 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1173 start_lock_event_timing ();
1178 Editor::start_lock_event_timing ()
1180 /* check if we should lock the GUI every 30 seconds */
1182 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1186 Editor::generic_event_handler (GdkEvent* ev)
1189 case GDK_BUTTON_PRESS:
1190 case GDK_BUTTON_RELEASE:
1191 case GDK_MOTION_NOTIFY:
1193 case GDK_KEY_RELEASE:
1194 if (contents().is_mapped()) {
1195 gettimeofday (&last_event_time, 0);
1199 case GDK_LEAVE_NOTIFY:
1200 switch (ev->crossing.detail) {
1201 case GDK_NOTIFY_UNKNOWN:
1202 case GDK_NOTIFY_INFERIOR:
1203 case GDK_NOTIFY_ANCESTOR:
1205 case GDK_NOTIFY_VIRTUAL:
1206 case GDK_NOTIFY_NONLINEAR:
1207 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1208 /* leaving window, so reset focus, thus ending any and
1209 all text entry operations.
1211 ARDOUR_UI::instance()->reset_focus (&contents());
1224 Editor::lock_timeout_callback ()
1226 struct timeval now, delta;
1228 gettimeofday (&now, 0);
1230 timersub (&now, &last_event_time, &delta);
1232 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1234 /* don't call again. Returning false will effectively
1235 disconnect us from the timer callback.
1237 unlock() will call start_lock_event_timing() to get things
1247 Editor::map_position_change (framepos_t frame)
1249 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1251 if (_session == 0) {
1255 if (_follow_playhead) {
1256 center_screen (frame);
1259 playhead_cursor->set_position (frame);
1263 Editor::center_screen (framepos_t frame)
1265 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1267 /* if we're off the page, then scroll.
1270 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1271 center_screen_internal (frame, page);
1276 Editor::center_screen_internal (framepos_t frame, float page)
1281 frame -= (framepos_t) page;
1286 reset_x_origin (frame);
1291 Editor::update_title ()
1293 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1295 if (!own_window()) {
1300 bool dirty = _session->dirty();
1302 string session_name;
1304 if (_session->snap_name() != _session->name()) {
1305 session_name = _session->snap_name();
1307 session_name = _session->name();
1311 session_name = "*" + session_name;
1314 WindowTitle title(session_name);
1315 title += S_("Window|Editor");
1316 title += Glib::get_application_name();
1317 own_window()->set_title (title.get_string());
1319 /* ::session_going_away() will have taken care of it */
1324 Editor::set_session (Session *t)
1326 SessionHandlePtr::set_session (t);
1332 _playlist_selector->set_session (_session);
1333 nudge_clock->set_session (_session);
1334 _summary->set_session (_session);
1335 _group_tabs->set_session (_session);
1336 _route_groups->set_session (_session);
1337 _regions->set_session (_session);
1338 _snapshots->set_session (_session);
1339 _routes->set_session (_session);
1340 _locations->set_session (_session);
1341 _time_info_box->set_session (_session);
1343 if (rhythm_ferret) {
1344 rhythm_ferret->set_session (_session);
1347 if (analysis_window) {
1348 analysis_window->set_session (_session);
1352 sfbrowser->set_session (_session);
1355 compute_fixed_ruler_scale ();
1357 /* Make sure we have auto loop and auto punch ranges */
1359 Location* loc = _session->locations()->auto_loop_location();
1361 loc->set_name (_("Loop"));
1364 loc = _session->locations()->auto_punch_location();
1367 loc->set_name (_("Punch"));
1370 refresh_location_display ();
1372 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1373 the selected Marker; this needs the LocationMarker list to be available.
1375 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1376 set_state (*node, Stateful::loading_state_version);
1378 /* catch up with the playhead */
1380 _session->request_locate (playhead_cursor->current_frame ());
1381 _pending_initial_locate = true;
1385 /* These signals can all be emitted by a non-GUI thread. Therefore the
1386 handlers for them must not attempt to directly interact with the GUI,
1387 but use PBD::Signal<T>::connect() which accepts an event loop
1388 ("context") where the handler will be asked to run.
1391 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1392 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1393 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1394 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1395 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1396 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1397 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1398 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1399 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1400 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1401 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1402 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1403 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1404 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1405 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1407 playhead_cursor->show ();
1409 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1410 Config->map_parameters (pc);
1411 _session->config.map_parameters (pc);
1413 restore_ruler_visibility ();
1414 //tempo_map_changed (PropertyChange (0));
1415 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1417 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1418 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1421 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1422 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1425 switch (_snap_type) {
1426 case SnapToRegionStart:
1427 case SnapToRegionEnd:
1428 case SnapToRegionSync:
1429 case SnapToRegionBoundary:
1430 build_region_boundary_cache ();
1437 /* catch up on selection of stripables (other selection state is lost
1438 * when a session is closed
1443 _session->get_stripables (sl);
1444 for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
1445 if ((*s)->presentation_info().selected()) {
1446 RouteTimeAxisView* rtav = get_route_view_by_route_id ((*s)->id());
1448 tl.push_back (rtav);
1453 selection->set (tl);
1456 /* register for undo history */
1457 _session->register_with_memento_command_factory(id(), this);
1458 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1460 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1462 LuaInstance::instance()->set_session(_session);
1464 start_updating_meters ();
1468 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1470 if (a->get_name() == "RegionMenu") {
1471 /* When the main menu's region menu is opened, we setup the actions so that they look right
1472 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1473 so we resensitize all region actions when the entered regionview or the region selection
1474 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1475 happens after the region context menu is opened. So we set a flag here, too.
1479 sensitize_the_right_region_actions ();
1480 _last_region_menu_was_main = true;
1485 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1487 using namespace Menu_Helpers;
1489 void (Editor::*emf)(FadeShape);
1490 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1493 images = &_xfade_in_images;
1494 emf = &Editor::set_fade_in_shape;
1496 images = &_xfade_out_images;
1497 emf = &Editor::set_fade_out_shape;
1502 _("Linear (for highly correlated material)"),
1503 *(*images)[FadeLinear],
1504 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1508 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1512 _("Constant power"),
1513 *(*images)[FadeConstantPower],
1514 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1517 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1522 *(*images)[FadeSymmetric],
1523 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1527 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1532 *(*images)[FadeSlow],
1533 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1536 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1541 *(*images)[FadeFast],
1542 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1545 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1548 /** Pop up a context menu for when the user clicks on a start crossfade */
1550 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1552 using namespace Menu_Helpers;
1553 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1558 MenuList& items (xfade_in_context_menu.items());
1561 if (arv->audio_region()->fade_in_active()) {
1562 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1564 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1567 items.push_back (SeparatorElem());
1568 fill_xfade_menu (items, true);
1570 xfade_in_context_menu.popup (button, time);
1573 /** Pop up a context menu for when the user clicks on an end crossfade */
1575 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1577 using namespace Menu_Helpers;
1578 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1583 MenuList& items (xfade_out_context_menu.items());
1586 if (arv->audio_region()->fade_out_active()) {
1587 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1589 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1592 items.push_back (SeparatorElem());
1593 fill_xfade_menu (items, false);
1595 xfade_out_context_menu.popup (button, time);
1599 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1601 using namespace Menu_Helpers;
1602 Menu* (Editor::*build_menu_function)();
1605 switch (item_type) {
1607 case RegionViewName:
1608 case RegionViewNameHighlight:
1609 case LeftFrameHandle:
1610 case RightFrameHandle:
1611 if (with_selection) {
1612 build_menu_function = &Editor::build_track_selection_context_menu;
1614 build_menu_function = &Editor::build_track_region_context_menu;
1619 if (with_selection) {
1620 build_menu_function = &Editor::build_track_selection_context_menu;
1622 build_menu_function = &Editor::build_track_context_menu;
1627 if (clicked_routeview->track()) {
1628 build_menu_function = &Editor::build_track_context_menu;
1630 build_menu_function = &Editor::build_track_bus_context_menu;
1635 /* probably shouldn't happen but if it does, we don't care */
1639 menu = (this->*build_menu_function)();
1640 menu->set_name ("ArdourContextMenu");
1642 /* now handle specific situations */
1644 switch (item_type) {
1646 case RegionViewName:
1647 case RegionViewNameHighlight:
1648 case LeftFrameHandle:
1649 case RightFrameHandle:
1650 if (!with_selection) {
1651 if (region_edit_menu_split_item) {
1652 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1653 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1655 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1658 if (region_edit_menu_split_multichannel_item) {
1659 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1660 region_edit_menu_split_multichannel_item->set_sensitive (true);
1662 region_edit_menu_split_multichannel_item->set_sensitive (false);
1675 /* probably shouldn't happen but if it does, we don't care */
1679 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1681 /* Bounce to disk */
1683 using namespace Menu_Helpers;
1684 MenuList& edit_items = menu->items();
1686 edit_items.push_back (SeparatorElem());
1688 switch (clicked_routeview->audio_track()->freeze_state()) {
1689 case AudioTrack::NoFreeze:
1690 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1693 case AudioTrack::Frozen:
1694 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1697 case AudioTrack::UnFrozen:
1698 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1704 if (item_type == StreamItem && clicked_routeview) {
1705 clicked_routeview->build_underlay_menu(menu);
1708 /* When the region menu is opened, we setup the actions so that they look right
1711 sensitize_the_right_region_actions ();
1712 _last_region_menu_was_main = false;
1714 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1715 menu->popup (button, time);
1719 Editor::build_track_context_menu ()
1721 using namespace Menu_Helpers;
1723 MenuList& edit_items = track_context_menu.items();
1726 add_dstream_context_items (edit_items);
1727 return &track_context_menu;
1731 Editor::build_track_bus_context_menu ()
1733 using namespace Menu_Helpers;
1735 MenuList& edit_items = track_context_menu.items();
1738 add_bus_context_items (edit_items);
1739 return &track_context_menu;
1743 Editor::build_track_region_context_menu ()
1745 using namespace Menu_Helpers;
1746 MenuList& edit_items = track_region_context_menu.items();
1749 /* we've just cleared the track region context menu, so the menu that these
1750 two items were on will have disappeared; stop them dangling.
1752 region_edit_menu_split_item = 0;
1753 region_edit_menu_split_multichannel_item = 0;
1755 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1758 boost::shared_ptr<Track> tr;
1759 boost::shared_ptr<Playlist> pl;
1761 if ((tr = rtv->track())) {
1762 add_region_context_items (edit_items, tr);
1766 add_dstream_context_items (edit_items);
1768 return &track_region_context_menu;
1772 Editor::loudness_analyze_region_selection ()
1777 Selection& s (PublicEditor::instance ().get_selection ());
1778 RegionSelection ars = s.regions;
1779 ARDOUR::AnalysisGraph ag (_session);
1780 framecnt_t total_work = 0;
1782 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1783 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1787 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1790 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1791 total_work += arv->region ()->length ();
1794 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1796 ag.set_total_frames (total_work);
1797 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1800 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1801 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1805 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1809 ag.analyze_region (ar);
1812 if (!ag.canceled ()) {
1813 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1819 Editor::loudness_analyze_range_selection ()
1824 Selection& s (PublicEditor::instance ().get_selection ());
1825 TimeSelection ts = s.time;
1826 ARDOUR::AnalysisGraph ag (_session);
1827 framecnt_t total_work = 0;
1829 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1830 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1834 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1838 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1839 total_work += j->length ();
1843 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1845 ag.set_total_frames (total_work);
1846 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1849 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1850 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1854 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1858 ag.analyze_range (rui->route (), pl, ts);
1861 if (!ag.canceled ()) {
1862 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1868 Editor::spectral_analyze_region_selection ()
1870 if (analysis_window == 0) {
1871 analysis_window = new AnalysisWindow();
1874 analysis_window->set_session(_session);
1876 analysis_window->show_all();
1879 analysis_window->set_regionmode();
1880 analysis_window->analyze();
1882 analysis_window->present();
1886 Editor::spectral_analyze_range_selection()
1888 if (analysis_window == 0) {
1889 analysis_window = new AnalysisWindow();
1892 analysis_window->set_session(_session);
1894 analysis_window->show_all();
1897 analysis_window->set_rangemode();
1898 analysis_window->analyze();
1900 analysis_window->present();
1904 Editor::build_track_selection_context_menu ()
1906 using namespace Menu_Helpers;
1907 MenuList& edit_items = track_selection_context_menu.items();
1908 edit_items.clear ();
1910 add_selection_context_items (edit_items);
1911 // edit_items.push_back (SeparatorElem());
1912 // add_dstream_context_items (edit_items);
1914 return &track_selection_context_menu;
1918 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1920 using namespace Menu_Helpers;
1922 /* OK, stick the region submenu at the top of the list, and then add
1926 RegionSelection rs = get_regions_from_selection_and_entered ();
1928 string::size_type pos = 0;
1929 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1931 /* we have to hack up the region name because "_" has a special
1932 meaning for menu titles.
1935 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1936 menu_item_name.replace (pos, 1, "__");
1940 if (_popup_region_menu_item == 0) {
1941 _popup_region_menu_item = new MenuItem (menu_item_name);
1942 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1943 _popup_region_menu_item->show ();
1945 _popup_region_menu_item->set_label (menu_item_name);
1948 /* No latering allowed in later is higher layering model */
1949 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1950 if (act && Config->get_layer_model() == LaterHigher) {
1951 act->set_sensitive (false);
1953 act->set_sensitive (true);
1956 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1958 edit_items.push_back (*_popup_region_menu_item);
1959 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1960 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1962 edit_items.push_back (SeparatorElem());
1965 /** Add context menu items relevant to selection ranges.
1966 * @param edit_items List to add the items to.
1969 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1971 using namespace Menu_Helpers;
1973 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1974 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1976 edit_items.push_back (SeparatorElem());
1977 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1979 edit_items.push_back (SeparatorElem());
1980 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1981 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1983 edit_items.push_back (SeparatorElem());
1985 edit_items.push_back (
1987 _("Move Range Start to Previous Region Boundary"),
1988 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1992 edit_items.push_back (
1994 _("Move Range Start to Next Region Boundary"),
1995 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1999 edit_items.push_back (
2001 _("Move Range End to Previous Region Boundary"),
2002 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
2006 edit_items.push_back (
2008 _("Move Range End to Next Region Boundary"),
2009 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
2013 edit_items.push_back (SeparatorElem());
2014 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
2015 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
2017 edit_items.push_back (SeparatorElem());
2018 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
2020 edit_items.push_back (SeparatorElem());
2021 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
2022 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
2023 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
2025 edit_items.push_back (SeparatorElem());
2026 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
2028 edit_items.push_back (SeparatorElem());
2029 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
2030 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
2032 edit_items.push_back (SeparatorElem());
2033 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
2034 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
2035 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
2036 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
2037 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
2038 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
2039 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2045 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2047 using namespace Menu_Helpers;
2051 Menu *play_menu = manage (new Menu);
2052 MenuList& play_items = play_menu->items();
2053 play_menu->set_name ("ArdourContextMenu");
2055 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2056 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2057 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2058 play_items.push_back (SeparatorElem());
2059 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2061 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2065 Menu *select_menu = manage (new Menu);
2066 MenuList& select_items = select_menu->items();
2067 select_menu->set_name ("ArdourContextMenu");
2069 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2070 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2071 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2072 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2073 select_items.push_back (SeparatorElem());
2074 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2075 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2076 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2077 select_items.push_back (SeparatorElem());
2078 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2079 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2080 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2081 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2082 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2083 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2084 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2086 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2090 Menu *cutnpaste_menu = manage (new Menu);
2091 MenuList& cutnpaste_items = cutnpaste_menu->items();
2092 cutnpaste_menu->set_name ("ArdourContextMenu");
2094 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2095 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2096 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2098 cutnpaste_items.push_back (SeparatorElem());
2100 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2101 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2103 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2105 /* Adding new material */
2107 edit_items.push_back (SeparatorElem());
2108 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2109 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2113 Menu *nudge_menu = manage (new Menu());
2114 MenuList& nudge_items = nudge_menu->items();
2115 nudge_menu->set_name ("ArdourContextMenu");
2117 edit_items.push_back (SeparatorElem());
2118 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2119 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2120 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2121 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2123 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2127 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2129 using namespace Menu_Helpers;
2133 Menu *play_menu = manage (new Menu);
2134 MenuList& play_items = play_menu->items();
2135 play_menu->set_name ("ArdourContextMenu");
2137 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2138 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2139 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2143 Menu *select_menu = manage (new Menu);
2144 MenuList& select_items = select_menu->items();
2145 select_menu->set_name ("ArdourContextMenu");
2147 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2148 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2149 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2150 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2151 select_items.push_back (SeparatorElem());
2152 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2153 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2154 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2155 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2157 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2161 Menu *cutnpaste_menu = manage (new Menu);
2162 MenuList& cutnpaste_items = cutnpaste_menu->items();
2163 cutnpaste_menu->set_name ("ArdourContextMenu");
2165 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2166 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2167 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2169 Menu *nudge_menu = manage (new Menu());
2170 MenuList& nudge_items = nudge_menu->items();
2171 nudge_menu->set_name ("ArdourContextMenu");
2173 edit_items.push_back (SeparatorElem());
2174 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2175 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2176 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2177 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2179 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2183 Editor::snap_type() const
2189 Editor::snap_musical() const
2191 switch (_snap_type) {
2192 case SnapToBeatDiv128:
2193 case SnapToBeatDiv64:
2194 case SnapToBeatDiv32:
2195 case SnapToBeatDiv28:
2196 case SnapToBeatDiv24:
2197 case SnapToBeatDiv20:
2198 case SnapToBeatDiv16:
2199 case SnapToBeatDiv14:
2200 case SnapToBeatDiv12:
2201 case SnapToBeatDiv10:
2202 case SnapToBeatDiv8:
2203 case SnapToBeatDiv7:
2204 case SnapToBeatDiv6:
2205 case SnapToBeatDiv5:
2206 case SnapToBeatDiv4:
2207 case SnapToBeatDiv3:
2208 case SnapToBeatDiv2:
2220 Editor::snap_mode() const
2226 Editor::set_snap_to (SnapType st)
2228 unsigned int snap_ind = (unsigned int)st;
2230 if (internal_editing()) {
2231 internal_snap_type = st;
2233 pre_internal_snap_type = st;
2238 if (snap_ind > snap_type_strings.size() - 1) {
2240 _snap_type = (SnapType)snap_ind;
2243 string str = snap_type_strings[snap_ind];
2245 if (str != snap_type_selector.get_text()) {
2246 snap_type_selector.set_text (str);
2251 switch (_snap_type) {
2252 case SnapToBeatDiv128:
2253 case SnapToBeatDiv64:
2254 case SnapToBeatDiv32:
2255 case SnapToBeatDiv28:
2256 case SnapToBeatDiv24:
2257 case SnapToBeatDiv20:
2258 case SnapToBeatDiv16:
2259 case SnapToBeatDiv14:
2260 case SnapToBeatDiv12:
2261 case SnapToBeatDiv10:
2262 case SnapToBeatDiv8:
2263 case SnapToBeatDiv7:
2264 case SnapToBeatDiv6:
2265 case SnapToBeatDiv5:
2266 case SnapToBeatDiv4:
2267 case SnapToBeatDiv3:
2268 case SnapToBeatDiv2: {
2269 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
2270 update_tempo_based_rulers ();
2274 case SnapToRegionStart:
2275 case SnapToRegionEnd:
2276 case SnapToRegionSync:
2277 case SnapToRegionBoundary:
2278 build_region_boundary_cache ();
2286 redisplay_tempo (false);
2288 SnapChanged (); /* EMIT SIGNAL */
2292 Editor::set_snap_mode (SnapMode mode)
2294 string str = snap_mode_strings[(int)mode];
2296 if (internal_editing()) {
2297 internal_snap_mode = mode;
2299 pre_internal_snap_mode = mode;
2304 if (str != snap_mode_selector.get_text ()) {
2305 snap_mode_selector.set_text (str);
2312 Editor::set_edit_point_preference (EditPoint ep, bool force)
2314 bool changed = (_edit_point != ep);
2317 if (Profile->get_mixbus())
2318 if (ep == EditAtSelectedMarker)
2319 ep = EditAtPlayhead;
2321 string str = edit_point_strings[(int)ep];
2322 if (str != edit_point_selector.get_text ()) {
2323 edit_point_selector.set_text (str);
2326 update_all_enter_cursors();
2328 if (!force && !changed) {
2332 const char* action=NULL;
2334 switch (_edit_point) {
2335 case EditAtPlayhead:
2336 action = "edit-at-playhead";
2338 case EditAtSelectedMarker:
2339 action = "edit-at-marker";
2342 action = "edit-at-mouse";
2346 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2348 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2352 bool in_track_canvas;
2354 if (!mouse_frame (foo, in_track_canvas)) {
2355 in_track_canvas = false;
2358 reset_canvas_action_sensitivity (in_track_canvas);
2364 Editor::set_state (const XMLNode& node, int version)
2366 XMLProperty const * prop;
2368 PBD::Unwinder<bool> nsi (no_save_instant, true);
2371 Tabbable::set_state (node, version);
2373 if (_session && (prop = node.property ("playhead"))) {
2375 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2377 playhead_cursor->set_position (pos);
2379 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2380 playhead_cursor->set_position (0);
2383 playhead_cursor->set_position (0);
2386 if ((prop = node.property ("mixer-width"))) {
2387 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2390 if ((prop = node.property ("zoom-focus"))) {
2391 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2393 zoom_focus_selection_done (zoom_focus);
2396 if ((prop = node.property ("zoom"))) {
2397 /* older versions of ardour used floating point samples_per_pixel */
2398 double f = PBD::atof (prop->value());
2399 reset_zoom (llrintf (f));
2401 reset_zoom (samples_per_pixel);
2404 if ((prop = node.property ("visible-track-count"))) {
2405 set_visible_track_count (PBD::atoi (prop->value()));
2408 if ((prop = node.property ("snap-to"))) {
2409 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2410 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2412 set_snap_to (_snap_type);
2415 if ((prop = node.property ("snap-mode"))) {
2416 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2417 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2418 * snap_mode_selection_done() will only mark an already active item as active
2419 * which does not trigger set_text().
2421 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2423 set_snap_mode (_snap_mode);
2426 if ((prop = node.property ("internal-snap-to"))) {
2427 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2430 if ((prop = node.property ("internal-snap-mode"))) {
2431 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2434 if ((prop = node.property ("pre-internal-snap-to"))) {
2435 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2438 if ((prop = node.property ("pre-internal-snap-mode"))) {
2439 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2442 if ((prop = node.property ("mouse-mode"))) {
2443 MouseMode m = str2mousemode(prop->value());
2444 set_mouse_mode (m, true);
2446 set_mouse_mode (MouseObject, true);
2449 if ((prop = node.property ("left-frame")) != 0) {
2451 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2455 reset_x_origin (pos);
2459 if ((prop = node.property ("y-origin")) != 0) {
2460 reset_y_origin (atof (prop->value ()));
2463 if ((prop = node.property ("join-object-range"))) {
2464 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2465 bool yn = string_is_affirmative (prop->value());
2467 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2468 tact->set_active (!yn);
2469 tact->set_active (yn);
2471 set_mouse_mode(mouse_mode, true);
2474 if ((prop = node.property ("edit-point"))) {
2475 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2477 set_edit_point_preference (_edit_point);
2480 if ((prop = node.property ("show-measures"))) {
2481 bool yn = string_is_affirmative (prop->value());
2482 _show_measures = yn;
2485 if ((prop = node.property ("follow-playhead"))) {
2486 bool yn = string_is_affirmative (prop->value());
2487 set_follow_playhead (yn);
2490 if ((prop = node.property ("stationary-playhead"))) {
2491 bool yn = string_is_affirmative (prop->value());
2492 set_stationary_playhead (yn);
2495 if ((prop = node.property ("region-list-sort-type"))) {
2496 RegionListSortType st;
2497 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2500 if ((prop = node.property ("show-editor-mixer"))) {
2502 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2505 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2506 bool yn = string_is_affirmative (prop->value());
2508 /* do it twice to force the change */
2510 tact->set_active (!yn);
2511 tact->set_active (yn);
2514 if ((prop = node.property ("show-editor-list"))) {
2516 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2519 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2520 bool yn = string_is_affirmative (prop->value());
2522 /* do it twice to force the change */
2524 tact->set_active (!yn);
2525 tact->set_active (yn);
2528 if ((prop = node.property (X_("editor-list-page")))) {
2529 _the_notebook.set_current_page (atoi (prop->value ()));
2532 if ((prop = node.property (X_("show-marker-lines")))) {
2533 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2535 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2536 bool yn = string_is_affirmative (prop->value ());
2538 tact->set_active (!yn);
2539 tact->set_active (yn);
2542 XMLNodeList children = node.children ();
2543 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2544 selection->set_state (**i, Stateful::current_state_version);
2545 _regions->set_state (**i);
2548 if ((prop = node.property ("maximised"))) {
2549 bool yn = string_is_affirmative (prop->value());
2550 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2552 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2553 bool fs = tact && tact->get_active();
2555 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2559 if ((prop = node.property ("nudge-clock-value"))) {
2561 sscanf (prop->value().c_str(), "%" PRId64, &f);
2562 nudge_clock->set (f);
2564 nudge_clock->set_mode (AudioClock::Timecode);
2565 nudge_clock->set (_session->frame_rate() * 5, true);
2570 * Not all properties may have been in XML, but
2571 * those that are linked to a private variable may need changing
2576 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2578 yn = _show_measures;
2579 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2580 /* do it twice to force the change */
2581 tact->set_active (!yn);
2582 tact->set_active (yn);
2585 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2586 yn = _follow_playhead;
2588 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2589 if (tact->get_active() != yn) {
2590 tact->set_active (yn);
2594 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2595 yn = _stationary_playhead;
2597 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2598 if (tact->get_active() != yn) {
2599 tact->set_active (yn);
2604 return LuaInstance::instance()->set_state(node);
2608 Editor::get_state ()
2610 XMLNode* node = new XMLNode (X_("Editor"));
2614 id().print (buf, sizeof (buf));
2615 node->add_property ("id", buf);
2617 node->add_child_nocopy (Tabbable::get_state());
2619 snprintf(buf,sizeof(buf), "%f", edit_pane.get_divider ());
2620 node->add_property("edit-horizontal-pane-pos", string(buf));
2621 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2622 snprintf(buf,sizeof(buf), "%f", editor_summary_pane.get_divider());
2623 node->add_property("edit-vertical-pane-pos", string(buf));
2625 maybe_add_mixer_strip_width (*node);
2627 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2629 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2630 node->add_property ("zoom", buf);
2631 node->add_property ("snap-to", enum_2_string (_snap_type));
2632 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2633 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2634 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2635 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2636 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2637 node->add_property ("edit-point", enum_2_string (_edit_point));
2638 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2639 node->add_property ("visible-track-count", buf);
2641 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2642 node->add_property ("playhead", buf);
2643 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2644 node->add_property ("left-frame", buf);
2645 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2646 node->add_property ("y-origin", buf);
2648 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2649 node->add_property ("maximised", _maximised ? "yes" : "no");
2650 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2651 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2652 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2653 node->add_property ("mouse-mode", enum2str(mouse_mode));
2654 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2656 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2658 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2659 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2662 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2664 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2665 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2668 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2669 node->add_property (X_("editor-list-page"), buf);
2671 if (button_bindings) {
2672 XMLNode* bb = new XMLNode (X_("Buttons"));
2673 button_bindings->save (*bb);
2674 node->add_child_nocopy (*bb);
2677 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2679 node->add_child_nocopy (selection->get_state ());
2680 node->add_child_nocopy (_regions->get_state ());
2682 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2683 node->add_property ("nudge-clock-value", buf);
2685 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2686 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2691 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2692 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2694 * @return pair: TimeAxisView that y is over, layer index.
2696 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2697 * in stacked or expanded region display mode, otherwise 0.
2699 std::pair<TimeAxisView *, double>
2700 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2702 if (!trackview_relative_offset) {
2703 y -= _trackview_group->canvas_origin().y;
2707 return std::make_pair ( (TimeAxisView *) 0, 0);
2710 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2712 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2719 return std::make_pair ( (TimeAxisView *) 0, 0);
2722 /** Snap a position to the grid, if appropriate, taking into account current
2723 * grid settings and also the state of any snap modifier keys that may be pressed.
2724 * @param start Position to snap.
2725 * @param event Event to get current key modifier information from, or 0.
2728 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2730 if (!_session || !event) {
2734 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2735 if (_snap_mode == SnapOff) {
2736 snap_to_internal (start, direction, for_mark);
2739 if (_snap_mode != SnapOff) {
2740 snap_to_internal (start, direction, for_mark);
2741 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2742 /* SnapOff, but we pressed the snap_delta modifier */
2743 snap_to_internal (start, direction, for_mark);
2749 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2751 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2755 snap_to_internal (start, direction, for_mark, ensure_snap);
2759 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2761 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2762 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2764 switch (_snap_type) {
2765 case SnapToTimecodeFrame:
2766 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2767 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2768 /* start is already on a whole timecode frame, do nothing */
2769 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2770 start = (framepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2772 start = (framepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2776 case SnapToTimecodeSeconds:
2777 if (_session->config.get_timecode_offset_negative()) {
2778 start += _session->config.get_timecode_offset ();
2780 start -= _session->config.get_timecode_offset ();
2782 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2783 (start % one_timecode_second == 0)) {
2784 /* start is already on a whole second, do nothing */
2785 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2786 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2788 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2791 if (_session->config.get_timecode_offset_negative()) {
2792 start -= _session->config.get_timecode_offset ();
2794 start += _session->config.get_timecode_offset ();
2798 case SnapToTimecodeMinutes:
2799 if (_session->config.get_timecode_offset_negative()) {
2800 start += _session->config.get_timecode_offset ();
2802 start -= _session->config.get_timecode_offset ();
2804 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2805 (start % one_timecode_minute == 0)) {
2806 /* start is already on a whole minute, do nothing */
2807 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2808 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2810 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2812 if (_session->config.get_timecode_offset_negative()) {
2813 start -= _session->config.get_timecode_offset ();
2815 start += _session->config.get_timecode_offset ();
2819 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2820 abort(); /*NOTREACHED*/
2825 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2827 const framepos_t one_second = _session->frame_rate();
2828 const framepos_t one_minute = _session->frame_rate() * 60;
2829 framepos_t presnap = start;
2833 switch (_snap_type) {
2834 case SnapToTimecodeFrame:
2835 case SnapToTimecodeSeconds:
2836 case SnapToTimecodeMinutes:
2837 return timecode_snap_to_internal (start, direction, for_mark);
2840 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2841 start % (one_second/75) == 0) {
2842 /* start is already on a whole CD frame, do nothing */
2843 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2844 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2846 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2851 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2852 start % one_second == 0) {
2853 /* start is already on a whole second, do nothing */
2854 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2855 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2857 start = (framepos_t) floor ((double) start / one_second) * one_second;
2862 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2863 start % one_minute == 0) {
2864 /* start is already on a whole minute, do nothing */
2865 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2866 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2868 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2873 start = _session->tempo_map().round_to_bar (start, direction);
2877 start = _session->tempo_map().round_to_beat (start, direction);
2880 case SnapToBeatDiv128:
2881 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 128, direction);
2883 case SnapToBeatDiv64:
2884 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 64, direction);
2886 case SnapToBeatDiv32:
2887 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 32, direction);
2889 case SnapToBeatDiv28:
2890 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 28, direction);
2892 case SnapToBeatDiv24:
2893 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 24, direction);
2895 case SnapToBeatDiv20:
2896 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 20, direction);
2898 case SnapToBeatDiv16:
2899 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 16, direction);
2901 case SnapToBeatDiv14:
2902 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 14, direction);
2904 case SnapToBeatDiv12:
2905 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 12, direction);
2907 case SnapToBeatDiv10:
2908 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 10, direction);
2910 case SnapToBeatDiv8:
2911 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 8, direction);
2913 case SnapToBeatDiv7:
2914 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 7, direction);
2916 case SnapToBeatDiv6:
2917 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 6, direction);
2919 case SnapToBeatDiv5:
2920 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 5, direction);
2922 case SnapToBeatDiv4:
2923 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 4, direction);
2925 case SnapToBeatDiv3:
2926 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 3, direction);
2928 case SnapToBeatDiv2:
2929 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 2, direction);
2937 _session->locations()->marks_either_side (start, before, after);
2939 if (before == max_framepos && after == max_framepos) {
2940 /* No marks to snap to, so just don't snap */
2942 } else if (before == max_framepos) {
2944 } else if (after == max_framepos) {
2946 } else if (before != max_framepos && after != max_framepos) {
2947 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2949 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2951 else if (direction == 0 ) {
2952 if ((start - before) < (after - start)) {
2962 case SnapToRegionStart:
2963 case SnapToRegionEnd:
2964 case SnapToRegionSync:
2965 case SnapToRegionBoundary:
2966 if (!region_boundary_cache.empty()) {
2968 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2969 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2971 if (direction > 0) {
2972 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2974 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2977 if (next != region_boundary_cache.begin ()) {
2982 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2983 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2985 if (start > (p + n) / 2) {
2994 switch (_snap_mode) {
3004 if (presnap > start) {
3005 if (presnap > (start + pixel_to_sample(snap_threshold))) {
3009 } else if (presnap < start) {
3010 if (presnap < (start - pixel_to_sample(snap_threshold))) {
3016 /* handled at entry */
3024 Editor::setup_toolbar ()
3026 HBox* mode_box = manage(new HBox);
3027 mode_box->set_border_width (2);
3028 mode_box->set_spacing(2);
3030 HBox* mouse_mode_box = manage (new HBox);
3031 HBox* mouse_mode_hbox = manage (new HBox);
3032 VBox* mouse_mode_vbox = manage (new VBox);
3033 Alignment* mouse_mode_align = manage (new Alignment);
3035 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3036 mouse_mode_size_group->add_widget (smart_mode_button);
3037 mouse_mode_size_group->add_widget (mouse_move_button);
3038 mouse_mode_size_group->add_widget (mouse_cut_button);
3039 mouse_mode_size_group->add_widget (mouse_select_button);
3040 mouse_mode_size_group->add_widget (mouse_timefx_button);
3041 mouse_mode_size_group->add_widget (mouse_audition_button);
3042 mouse_mode_size_group->add_widget (mouse_draw_button);
3043 mouse_mode_size_group->add_widget (mouse_content_button);
3045 if (!Profile->get_mixbus()) {
3046 mouse_mode_size_group->add_widget (zoom_in_button);
3047 mouse_mode_size_group->add_widget (zoom_out_button);
3048 mouse_mode_size_group->add_widget (zoom_out_full_button);
3049 mouse_mode_size_group->add_widget (zoom_focus_selector);
3050 mouse_mode_size_group->add_widget (tav_shrink_button);
3051 mouse_mode_size_group->add_widget (tav_expand_button);
3053 mouse_mode_size_group->add_widget (zoom_preset_selector);
3054 mouse_mode_size_group->add_widget (visible_tracks_selector);
3057 mouse_mode_size_group->add_widget (snap_type_selector);
3058 mouse_mode_size_group->add_widget (snap_mode_selector);
3060 mouse_mode_size_group->add_widget (edit_point_selector);
3061 mouse_mode_size_group->add_widget (edit_mode_selector);
3063 mouse_mode_size_group->add_widget (*nudge_clock);
3064 mouse_mode_size_group->add_widget (nudge_forward_button);
3065 mouse_mode_size_group->add_widget (nudge_backward_button);
3067 mouse_mode_hbox->set_spacing (2);
3069 if (!ARDOUR::Profile->get_trx()) {
3070 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3073 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3074 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3076 if (!ARDOUR::Profile->get_mixbus()) {
3077 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3080 if (!ARDOUR::Profile->get_trx()) {
3081 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3082 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3083 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3084 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3087 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3089 mouse_mode_align->add (*mouse_mode_vbox);
3090 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3092 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3094 edit_mode_selector.set_name ("mouse mode button");
3096 if (!ARDOUR::Profile->get_trx()) {
3097 mode_box->pack_start (edit_mode_selector, false, false);
3100 mode_box->pack_start (*mouse_mode_box, false, false);
3104 _zoom_box.set_spacing (2);
3105 _zoom_box.set_border_width (2);
3109 zoom_preset_selector.set_name ("zoom button");
3110 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
3112 zoom_in_button.set_name ("zoom button");
3113 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3114 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3115 zoom_in_button.set_related_action (act);
3117 zoom_out_button.set_name ("zoom button");
3118 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3119 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3120 zoom_out_button.set_related_action (act);
3122 zoom_out_full_button.set_name ("zoom button");
3123 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3124 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3125 zoom_out_full_button.set_related_action (act);
3127 zoom_focus_selector.set_name ("zoom button");
3129 if (ARDOUR::Profile->get_mixbus()) {
3130 _zoom_box.pack_start (zoom_preset_selector, false, false);
3131 } else if (ARDOUR::Profile->get_trx()) {
3132 mode_box->pack_start (zoom_out_button, false, false);
3133 mode_box->pack_start (zoom_in_button, false, false);
3135 _zoom_box.pack_start (zoom_out_button, false, false);
3136 _zoom_box.pack_start (zoom_in_button, false, false);
3137 _zoom_box.pack_start (zoom_out_full_button, false, false);
3138 _zoom_box.pack_start (zoom_focus_selector, false, false);
3141 /* Track zoom buttons */
3142 _track_box.set_spacing (2);
3143 _track_box.set_border_width (2);
3145 visible_tracks_selector.set_name ("zoom button");
3146 if (Profile->get_mixbus()) {
3147 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3149 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3152 tav_expand_button.set_name ("zoom button");
3153 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3154 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3155 tav_expand_button.set_related_action (act);
3157 tav_shrink_button.set_name ("zoom button");
3158 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3159 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3160 tav_shrink_button.set_related_action (act);
3162 if (ARDOUR::Profile->get_mixbus()) {
3163 _track_box.pack_start (visible_tracks_selector);
3164 } else if (ARDOUR::Profile->get_trx()) {
3165 _track_box.pack_start (tav_shrink_button);
3166 _track_box.pack_start (tav_expand_button);
3168 _track_box.pack_start (visible_tracks_selector);
3169 _track_box.pack_start (tav_shrink_button);
3170 _track_box.pack_start (tav_expand_button);
3173 snap_box.set_spacing (2);
3174 snap_box.set_border_width (2);
3176 snap_type_selector.set_name ("mouse mode button");
3178 snap_mode_selector.set_name ("mouse mode button");
3180 edit_point_selector.set_name ("mouse mode button");
3182 snap_box.pack_start (snap_mode_selector, false, false);
3183 snap_box.pack_start (snap_type_selector, false, false);
3186 HBox *ep_box = manage (new HBox);
3187 ep_box->set_spacing (2);
3188 ep_box->set_border_width (2);
3190 ep_box->pack_start (edit_point_selector, false, false);
3194 HBox *nudge_box = manage (new HBox);
3195 nudge_box->set_spacing (2);
3196 nudge_box->set_border_width (2);
3198 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3199 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3201 nudge_box->pack_start (nudge_backward_button, false, false);
3202 nudge_box->pack_start (nudge_forward_button, false, false);
3203 nudge_box->pack_start (*nudge_clock, false, false);
3206 /* Pack everything in... */
3208 toolbar_hbox.set_spacing (2);
3209 toolbar_hbox.set_border_width (2);
3211 toolbar_hbox.pack_start (*mode_box, false, false);
3213 if (!ARDOUR::Profile->get_trx()) {
3215 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3217 toolbar_hbox.pack_start (_zoom_box, false, false);
3219 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3221 toolbar_hbox.pack_start (_track_box, false, false);
3223 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3225 toolbar_hbox.pack_start (snap_box, false, false);
3227 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3229 toolbar_hbox.pack_start (*ep_box, false, false);
3231 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3233 toolbar_hbox.pack_start (*nudge_box, false, false);
3236 toolbar_hbox.show_all ();
3240 Editor::build_edit_point_menu ()
3242 using namespace Menu_Helpers;
3244 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3245 if(!Profile->get_mixbus())
3246 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3247 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3249 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3253 Editor::build_edit_mode_menu ()
3255 using namespace Menu_Helpers;
3257 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3258 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3259 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3260 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3262 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3266 Editor::build_snap_mode_menu ()
3268 using namespace Menu_Helpers;
3270 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3271 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3272 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3274 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3278 Editor::build_snap_type_menu ()
3280 using namespace Menu_Helpers;
3282 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3283 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3284 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3285 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3286 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3287 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3288 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3289 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3290 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3291 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3292 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3293 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3294 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3295 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3296 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3297 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3298 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3299 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3300 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3301 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3302 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3303 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3304 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3305 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3306 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3307 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3308 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3309 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3310 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3311 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3313 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3318 Editor::setup_tooltips ()
3320 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3321 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3322 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3323 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3324 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3325 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3326 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3327 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3328 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3329 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3330 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3331 set_tooltip (zoom_in_button, _("Zoom In"));
3332 set_tooltip (zoom_out_button, _("Zoom Out"));
3333 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3334 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3335 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3336 set_tooltip (tav_expand_button, _("Expand Tracks"));
3337 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3338 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3339 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3340 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3341 set_tooltip (edit_point_selector, _("Edit Point"));
3342 set_tooltip (edit_mode_selector, _("Edit Mode"));
3343 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3347 Editor::convert_drop_to_paths (
3348 vector<string>& paths,
3349 const RefPtr<Gdk::DragContext>& /*context*/,
3352 const SelectionData& data,
3356 if (_session == 0) {
3360 vector<string> uris = data.get_uris();
3364 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3365 are actually URI lists. So do it by hand.
3368 if (data.get_target() != "text/plain") {
3372 /* Parse the "uri-list" format that Nautilus provides,
3373 where each pathname is delimited by \r\n.
3375 THERE MAY BE NO NULL TERMINATING CHAR!!!
3378 string txt = data.get_text();
3382 p = (char *) malloc (txt.length() + 1);
3383 txt.copy (p, txt.length(), 0);
3384 p[txt.length()] = '\0';
3390 while (g_ascii_isspace (*p))
3394 while (*q && (*q != '\n') && (*q != '\r')) {
3401 while (q > p && g_ascii_isspace (*q))
3406 uris.push_back (string (p, q - p + 1));
3410 p = strchr (p, '\n');
3422 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3423 if ((*i).substr (0,7) == "file://") {
3424 paths.push_back (Glib::filename_from_uri (*i));
3432 Editor::new_tempo_section ()
3437 Editor::map_transport_state ()
3439 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3441 if (_session && _session->transport_stopped()) {
3442 have_pending_keyboard_selection = false;
3445 update_loop_range_view ();
3451 Editor::begin_selection_op_history ()
3453 selection_op_cmd_depth = 0;
3454 selection_op_history_it = 0;
3456 while(!selection_op_history.empty()) {
3457 delete selection_op_history.front();
3458 selection_op_history.pop_front();
3461 selection_undo_action->set_sensitive (false);
3462 selection_redo_action->set_sensitive (false);
3463 selection_op_history.push_front (&_selection_memento->get_state ());
3467 Editor::begin_reversible_selection_op (string name)
3470 //cerr << name << endl;
3471 /* begin/commit pairs can be nested */
3472 selection_op_cmd_depth++;
3477 Editor::commit_reversible_selection_op ()
3480 if (selection_op_cmd_depth == 1) {
3482 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3484 The user has undone some selection ops and then made a new one,
3485 making anything earlier in the list invalid.
3488 list<XMLNode *>::iterator it = selection_op_history.begin();
3489 list<XMLNode *>::iterator e_it = it;
3490 advance (e_it, selection_op_history_it);
3492 for ( ; it != e_it; ++it) {
3495 selection_op_history.erase (selection_op_history.begin(), e_it);
3498 selection_op_history.push_front (&_selection_memento->get_state ());
3499 selection_op_history_it = 0;
3501 selection_undo_action->set_sensitive (true);
3502 selection_redo_action->set_sensitive (false);
3505 if (selection_op_cmd_depth > 0) {
3506 selection_op_cmd_depth--;
3512 Editor::undo_selection_op ()
3515 selection_op_history_it++;
3517 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3518 if (n == selection_op_history_it) {
3519 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3520 selection_redo_action->set_sensitive (true);
3524 /* is there an earlier entry? */
3525 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3526 selection_undo_action->set_sensitive (false);
3532 Editor::redo_selection_op ()
3535 if (selection_op_history_it > 0) {
3536 selection_op_history_it--;
3539 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3540 if (n == selection_op_history_it) {
3541 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3542 selection_undo_action->set_sensitive (true);
3547 if (selection_op_history_it == 0) {
3548 selection_redo_action->set_sensitive (false);
3554 Editor::begin_reversible_command (string name)
3557 before.push_back (&_selection_memento->get_state ());
3558 _session->begin_reversible_command (name);
3563 Editor::begin_reversible_command (GQuark q)
3566 before.push_back (&_selection_memento->get_state ());
3567 _session->begin_reversible_command (q);
3572 Editor::abort_reversible_command ()
3575 while(!before.empty()) {
3576 delete before.front();
3579 _session->abort_reversible_command ();
3584 Editor::commit_reversible_command ()
3587 if (before.size() == 1) {
3588 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3589 redo_action->set_sensitive(false);
3590 undo_action->set_sensitive(true);
3591 begin_selection_op_history ();
3594 if (before.empty()) {
3595 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3600 _session->commit_reversible_command ();
3605 Editor::history_changed ()
3609 if (undo_action && _session) {
3610 if (_session->undo_depth() == 0) {
3611 label = S_("Command|Undo");
3613 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3615 undo_action->property_label() = label;
3618 if (redo_action && _session) {
3619 if (_session->redo_depth() == 0) {
3621 redo_action->set_sensitive (false);
3623 label = string_compose(_("Redo (%1)"), _session->next_redo());
3624 redo_action->set_sensitive (true);
3626 redo_action->property_label() = label;
3631 Editor::duplicate_range (bool with_dialog)
3635 RegionSelection rs = get_regions_from_selection_and_entered ();
3637 if ( selection->time.length() == 0 && rs.empty()) {
3643 ArdourDialog win (_("Duplicate"));
3644 Label label (_("Number of duplications:"));
3645 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3646 SpinButton spinner (adjustment, 0.0, 1);
3649 win.get_vbox()->set_spacing (12);
3650 win.get_vbox()->pack_start (hbox);
3651 hbox.set_border_width (6);
3652 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3654 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3655 place, visually. so do this by hand.
3658 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3659 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3660 spinner.grab_focus();
3666 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3667 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3668 win.set_default_response (RESPONSE_ACCEPT);
3670 spinner.grab_focus ();
3672 switch (win.run ()) {
3673 case RESPONSE_ACCEPT:
3679 times = adjustment.get_value();
3682 if ((current_mouse_mode() == Editing::MouseRange)) {
3683 if (selection->time.length()) {
3684 duplicate_selection (times);
3686 } else if (get_smart_mode()) {
3687 if (selection->time.length()) {
3688 duplicate_selection (times);
3690 duplicate_some_regions (rs, times);
3692 duplicate_some_regions (rs, times);
3697 Editor::set_edit_mode (EditMode m)
3699 Config->set_edit_mode (m);
3703 Editor::cycle_edit_mode ()
3705 switch (Config->get_edit_mode()) {
3707 Config->set_edit_mode (Ripple);
3711 Config->set_edit_mode (Lock);
3714 Config->set_edit_mode (Slide);
3720 Editor::edit_mode_selection_done ( EditMode m )
3722 Config->set_edit_mode ( m );
3726 Editor::snap_type_selection_done (SnapType snaptype)
3728 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3730 ract->set_active ();
3735 Editor::snap_mode_selection_done (SnapMode mode)
3737 RefPtr<RadioAction> ract = snap_mode_action (mode);
3740 ract->set_active (true);
3745 Editor::cycle_edit_point (bool with_marker)
3747 if(Profile->get_mixbus())
3748 with_marker = false;
3750 switch (_edit_point) {
3752 set_edit_point_preference (EditAtPlayhead);
3754 case EditAtPlayhead:
3756 set_edit_point_preference (EditAtSelectedMarker);
3758 set_edit_point_preference (EditAtMouse);
3761 case EditAtSelectedMarker:
3762 set_edit_point_preference (EditAtMouse);
3768 Editor::edit_point_selection_done (EditPoint ep)
3770 set_edit_point_preference ( ep );
3774 Editor::build_zoom_focus_menu ()
3776 using namespace Menu_Helpers;
3778 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3779 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3780 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3781 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3782 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3783 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3785 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3789 Editor::zoom_focus_selection_done ( ZoomFocus f )
3791 RefPtr<RadioAction> ract = zoom_focus_action (f);
3793 ract->set_active ();
3798 Editor::build_track_count_menu ()
3800 using namespace Menu_Helpers;
3802 if (!Profile->get_mixbus()) {
3803 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3804 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3805 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3806 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3807 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3808 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3809 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3810 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3811 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3812 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3813 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3814 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3815 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3817 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3818 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3819 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3820 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3821 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3822 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3823 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3824 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3825 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3826 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3828 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3829 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3830 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3831 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3832 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3833 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3834 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3835 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3836 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3837 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3838 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3843 Editor::set_zoom_preset (int64_t ms)
3846 temporal_zoom_session();
3850 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3851 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3855 Editor::set_visible_track_count (int32_t n)
3857 _visible_track_count = n;
3859 /* if the canvas hasn't really been allocated any size yet, just
3860 record the desired number of visible tracks and return. when canvas
3861 allocation happens, we will get called again and then we can do the
3865 if (_visible_canvas_height <= 1) {
3871 DisplaySuspender ds;
3873 if (_visible_track_count > 0) {
3874 h = trackviews_height() / _visible_track_count;
3875 std::ostringstream s;
3876 s << _visible_track_count;
3878 } else if (_visible_track_count == 0) {
3880 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3881 if ((*i)->marked_for_display()) {
3885 h = trackviews_height() / n;
3888 /* negative value means that the visible track count has
3889 been overridden by explicit track height changes.
3891 visible_tracks_selector.set_text (X_("*"));
3895 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3896 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3899 if (str != visible_tracks_selector.get_text()) {
3900 visible_tracks_selector.set_text (str);
3905 Editor::override_visible_track_count ()
3907 _visible_track_count = -1;
3908 visible_tracks_selector.set_text ( _("*") );
3912 Editor::edit_controls_button_release (GdkEventButton* ev)
3914 if (Keyboard::is_context_menu_event (ev)) {
3915 ARDOUR_UI::instance()->add_route ();
3916 } else if (ev->button == 1) {
3917 selection->clear_tracks ();
3924 Editor::mouse_select_button_release (GdkEventButton* ev)
3926 /* this handles just right-clicks */
3928 if (ev->button != 3) {
3936 Editor::set_zoom_focus (ZoomFocus f)
3938 string str = zoom_focus_strings[(int)f];
3940 if (str != zoom_focus_selector.get_text()) {
3941 zoom_focus_selector.set_text (str);
3944 if (zoom_focus != f) {
3951 Editor::cycle_zoom_focus ()
3953 switch (zoom_focus) {
3955 set_zoom_focus (ZoomFocusRight);
3957 case ZoomFocusRight:
3958 set_zoom_focus (ZoomFocusCenter);
3960 case ZoomFocusCenter:
3961 set_zoom_focus (ZoomFocusPlayhead);
3963 case ZoomFocusPlayhead:
3964 set_zoom_focus (ZoomFocusMouse);
3966 case ZoomFocusMouse:
3967 set_zoom_focus (ZoomFocusEdit);
3970 set_zoom_focus (ZoomFocusLeft);
3976 Editor::set_show_measures (bool yn)
3978 if (_show_measures != yn) {
3981 if ((_show_measures = yn) == true) {
3983 tempo_lines->show();
3986 std::vector<TempoMap::BBTPoint> grid;
3987 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3988 draw_measures (grid);
3996 Editor::toggle_follow_playhead ()
3998 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
4000 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4001 set_follow_playhead (tact->get_active());
4005 /** @param yn true to follow playhead, otherwise false.
4006 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4009 Editor::set_follow_playhead (bool yn, bool catch_up)
4011 if (_follow_playhead != yn) {
4012 if ((_follow_playhead = yn) == true && catch_up) {
4014 reset_x_origin_to_follow_playhead ();
4021 Editor::toggle_stationary_playhead ()
4023 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4025 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4026 set_stationary_playhead (tact->get_active());
4031 Editor::set_stationary_playhead (bool yn)
4033 if (_stationary_playhead != yn) {
4034 if ((_stationary_playhead = yn) == true) {
4036 // FIXME need a 3.0 equivalent of this 2.X call
4037 // update_current_screen ();
4044 Editor::playlist_selector () const
4046 return *_playlist_selector;
4050 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4052 if (paste_count == 0) {
4053 /* don't bother calculating an offset that will be zero anyway */
4057 /* calculate basic unsnapped multi-paste offset */
4058 framecnt_t offset = paste_count * duration;
4060 /* snap offset so pos + offset is aligned to the grid */
4061 framepos_t offset_pos = pos + offset;
4062 snap_to(offset_pos, RoundUpMaybe);
4063 offset = offset_pos - pos;
4069 Editor::get_grid_beat_divisions(framepos_t position)
4071 switch (_snap_type) {
4072 case SnapToBeatDiv128: return 128;
4073 case SnapToBeatDiv64: return 64;
4074 case SnapToBeatDiv32: return 32;
4075 case SnapToBeatDiv28: return 28;
4076 case SnapToBeatDiv24: return 24;
4077 case SnapToBeatDiv20: return 20;
4078 case SnapToBeatDiv16: return 16;
4079 case SnapToBeatDiv14: return 14;
4080 case SnapToBeatDiv12: return 12;
4081 case SnapToBeatDiv10: return 10;
4082 case SnapToBeatDiv8: return 8;
4083 case SnapToBeatDiv7: return 7;
4084 case SnapToBeatDiv6: return 6;
4085 case SnapToBeatDiv5: return 5;
4086 case SnapToBeatDiv4: return 4;
4087 case SnapToBeatDiv3: return 3;
4088 case SnapToBeatDiv2: return 2;
4094 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4095 if the grid is non-musical, returns 0.
4096 if the grid is snapped to bars, returns -1.
4097 @param event_state the current keyboard modifier mask.
4100 Editor::get_grid_music_divisions (uint32_t event_state)
4102 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4106 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4110 switch (_snap_type) {
4111 case SnapToBeatDiv128: return 128;
4112 case SnapToBeatDiv64: return 64;
4113 case SnapToBeatDiv32: return 32;
4114 case SnapToBeatDiv28: return 28;
4115 case SnapToBeatDiv24: return 24;
4116 case SnapToBeatDiv20: return 20;
4117 case SnapToBeatDiv16: return 16;
4118 case SnapToBeatDiv14: return 14;
4119 case SnapToBeatDiv12: return 12;
4120 case SnapToBeatDiv10: return 10;
4121 case SnapToBeatDiv8: return 8;
4122 case SnapToBeatDiv7: return 7;
4123 case SnapToBeatDiv6: return 6;
4124 case SnapToBeatDiv5: return 5;
4125 case SnapToBeatDiv4: return 4;
4126 case SnapToBeatDiv3: return 3;
4127 case SnapToBeatDiv2: return 2;
4128 case SnapToBeat: return 1;
4129 case SnapToBar : return -1;
4136 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4140 const unsigned divisions = get_grid_beat_divisions(position);
4142 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4145 switch (_snap_type) {
4147 return Evoral::Beats(4.0 / _session->tempo_map().meter_at_frame (position).note_divisor());
4150 const Meter& m = _session->tempo_map().meter_at_frame (position);
4151 return Evoral::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4159 return Evoral::Beats();
4163 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4167 ret = nudge_clock->current_duration (pos);
4168 next = ret + 1; /* XXXX fix me */
4174 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4176 ArdourDialog dialog (_("Playlist Deletion"));
4177 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4178 "If it is kept, its audio files will not be cleaned.\n"
4179 "If it is deleted, audio files used by it alone will be cleaned."),
4182 dialog.set_position (WIN_POS_CENTER);
4183 dialog.get_vbox()->pack_start (label);
4187 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4188 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4189 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4190 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4191 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4193 // by default gtk uses the left most button
4194 keep->grab_focus ();
4196 switch (dialog.run ()) {
4198 /* keep this and all remaining ones */
4203 /* delete this and all others */
4207 case RESPONSE_ACCEPT:
4208 /* delete the playlist */
4212 case RESPONSE_REJECT:
4213 /* keep the playlist */
4225 Editor::audio_region_selection_covers (framepos_t where)
4227 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4228 if ((*a)->region()->covers (where)) {
4237 Editor::prepare_for_cleanup ()
4239 cut_buffer->clear_regions ();
4240 cut_buffer->clear_playlists ();
4242 selection->clear_regions ();
4243 selection->clear_playlists ();
4245 _regions->suspend_redisplay ();
4249 Editor::finish_cleanup ()
4251 _regions->resume_redisplay ();
4255 Editor::transport_loop_location()
4258 return _session->locations()->auto_loop_location();
4265 Editor::transport_punch_location()
4268 return _session->locations()->auto_punch_location();
4275 Editor::control_layout_scroll (GdkEventScroll* ev)
4277 /* Just forward to the normal canvas scroll method. The coordinate
4278 systems are different but since the canvas is always larger than the
4279 track headers, and aligned with the trackview area, this will work.
4281 In the not too distant future this layout is going away anyway and
4282 headers will be on the canvas.
4284 return canvas_scroll_event (ev, false);
4288 Editor::session_state_saved (string)
4291 _snapshots->redisplay ();
4295 Editor::maximise_editing_space ()
4301 Gtk::Window* toplevel = current_toplevel();
4304 toplevel->fullscreen ();
4310 Editor::restore_editing_space ()
4316 Gtk::Window* toplevel = current_toplevel();
4319 toplevel->unfullscreen();
4325 * Make new playlists for a given track and also any others that belong
4326 * to the same active route group with the `select' property.
4331 Editor::new_playlists (TimeAxisView* v)
4333 begin_reversible_command (_("new playlists"));
4334 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4335 _session->playlists->get (playlists);
4336 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4337 commit_reversible_command ();
4341 * Use a copy of the current playlist for a given track and also any others that belong
4342 * to the same active route group with the `select' property.
4347 Editor::copy_playlists (TimeAxisView* v)
4349 begin_reversible_command (_("copy playlists"));
4350 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4351 _session->playlists->get (playlists);
4352 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4353 commit_reversible_command ();
4356 /** Clear the current playlist for a given track and also any others that belong
4357 * to the same active route group with the `select' property.
4362 Editor::clear_playlists (TimeAxisView* v)
4364 begin_reversible_command (_("clear playlists"));
4365 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4366 _session->playlists->get (playlists);
4367 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4368 commit_reversible_command ();
4372 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4374 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4378 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4380 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4384 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4386 atv.clear_playlist ();
4390 Editor::get_y_origin () const
4392 return vertical_adjustment.get_value ();
4395 /** Queue up a change to the viewport x origin.
4396 * @param frame New x origin.
4399 Editor::reset_x_origin (framepos_t frame)
4401 pending_visual_change.add (VisualChange::TimeOrigin);
4402 pending_visual_change.time_origin = frame;
4403 ensure_visual_change_idle_handler ();
4407 Editor::reset_y_origin (double y)
4409 pending_visual_change.add (VisualChange::YOrigin);
4410 pending_visual_change.y_origin = y;
4411 ensure_visual_change_idle_handler ();
4415 Editor::reset_zoom (framecnt_t spp)
4417 if (spp == samples_per_pixel) {
4421 pending_visual_change.add (VisualChange::ZoomLevel);
4422 pending_visual_change.samples_per_pixel = spp;
4423 ensure_visual_change_idle_handler ();
4427 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4429 reset_x_origin (frame);
4432 if (!no_save_visual) {
4433 undo_visual_stack.push_back (current_visual_state(false));
4437 Editor::VisualState::VisualState (bool with_tracks)
4438 : gui_state (with_tracks ? new GUIObjectState : 0)
4442 Editor::VisualState::~VisualState ()
4447 Editor::VisualState*
4448 Editor::current_visual_state (bool with_tracks)
4450 VisualState* vs = new VisualState (with_tracks);
4451 vs->y_position = vertical_adjustment.get_value();
4452 vs->samples_per_pixel = samples_per_pixel;
4453 vs->leftmost_frame = leftmost_frame;
4454 vs->zoom_focus = zoom_focus;
4457 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4464 Editor::undo_visual_state ()
4466 if (undo_visual_stack.empty()) {
4470 VisualState* vs = undo_visual_stack.back();
4471 undo_visual_stack.pop_back();
4474 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4477 use_visual_state (*vs);
4482 Editor::redo_visual_state ()
4484 if (redo_visual_stack.empty()) {
4488 VisualState* vs = redo_visual_stack.back();
4489 redo_visual_stack.pop_back();
4491 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4492 // why do we check here?
4493 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4496 use_visual_state (*vs);
4501 Editor::swap_visual_state ()
4503 if (undo_visual_stack.empty()) {
4504 redo_visual_state ();
4506 undo_visual_state ();
4511 Editor::use_visual_state (VisualState& vs)
4513 PBD::Unwinder<bool> nsv (no_save_visual, true);
4514 DisplaySuspender ds;
4516 vertical_adjustment.set_value (vs.y_position);
4518 set_zoom_focus (vs.zoom_focus);
4519 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4522 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4524 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4525 (*i)->clear_property_cache();
4526 (*i)->reset_visual_state ();
4530 _routes->update_visibility ();
4533 /** This is the core function that controls the zoom level of the canvas. It is called
4534 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4535 * @param spp new number of samples per pixel
4538 Editor::set_samples_per_pixel (framecnt_t spp)
4544 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4545 const framecnt_t lots_of_pixels = 4000;
4547 /* if the zoom level is greater than what you'd get trying to display 3
4548 * days of audio on a really big screen, then it's too big.
4551 if (spp * lots_of_pixels > three_days) {
4555 samples_per_pixel = spp;
4558 tempo_lines->tempo_map_changed();
4561 bool const showing_time_selection = selection->time.length() > 0;
4563 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4564 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4565 (*i)->reshow_selection (selection->time);
4569 ZoomChanged (); /* EMIT_SIGNAL */
4571 ArdourCanvas::GtkCanvasViewport* c;
4573 c = get_track_canvas();
4575 c->canvas()->zoomed ();
4578 if (playhead_cursor) {
4579 playhead_cursor->set_position (playhead_cursor->current_frame ());
4582 refresh_location_display();
4583 _summary->set_overlays_dirty ();
4585 update_marker_labels ();
4591 Editor::playhead_cursor_sample () const
4593 return playhead_cursor->current_frame();
4597 Editor::queue_visual_videotimeline_update ()
4600 * pending_visual_change.add (VisualChange::VideoTimeline);
4601 * or maybe even more specific: which videotimeline-image
4602 * currently it calls update_video_timeline() to update
4603 * _all outdated_ images on the video-timeline.
4604 * see 'exposeimg()' in video_image_frame.cc
4606 ensure_visual_change_idle_handler ();
4610 Editor::ensure_visual_change_idle_handler ()
4612 if (pending_visual_change.idle_handler_id < 0) {
4613 // see comment in add_to_idle_resize above.
4614 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4615 pending_visual_change.being_handled = false;
4620 Editor::_idle_visual_changer (void* arg)
4622 return static_cast<Editor*>(arg)->idle_visual_changer ();
4626 Editor::idle_visual_changer ()
4628 /* set_horizontal_position() below (and maybe other calls) call
4629 gtk_main_iteration(), so it's possible that a signal will be handled
4630 half-way through this method. If this signal wants an
4631 idle_visual_changer we must schedule another one after this one, so
4632 mark the idle_handler_id as -1 here to allow that. Also make a note
4633 that we are doing the visual change, so that changes in response to
4634 super-rapid-screen-update can be dropped if we are still processing
4638 pending_visual_change.idle_handler_id = -1;
4639 pending_visual_change.being_handled = true;
4641 VisualChange vc = pending_visual_change;
4643 pending_visual_change.pending = (VisualChange::Type) 0;
4645 visual_changer (vc);
4647 pending_visual_change.being_handled = false;
4649 return 0; /* this is always a one-shot call */
4653 Editor::visual_changer (const VisualChange& vc)
4655 double const last_time_origin = horizontal_position ();
4657 if (vc.pending & VisualChange::ZoomLevel) {
4658 set_samples_per_pixel (vc.samples_per_pixel);
4660 compute_fixed_ruler_scale ();
4662 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4663 update_tempo_based_rulers ();
4665 update_video_timeline();
4668 if (vc.pending & VisualChange::TimeOrigin) {
4669 set_horizontal_position (vc.time_origin / samples_per_pixel);
4672 if (vc.pending & VisualChange::YOrigin) {
4673 vertical_adjustment.set_value (vc.y_origin);
4676 if (last_time_origin == horizontal_position ()) {
4677 /* changed signal not emitted */
4678 update_fixed_rulers ();
4679 redisplay_tempo (true);
4682 if (!(vc.pending & VisualChange::ZoomLevel)) {
4683 update_video_timeline();
4686 _summary->set_overlays_dirty ();
4689 struct EditorOrderTimeAxisSorter {
4690 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4691 return a->order () < b->order ();
4696 Editor::sort_track_selection (TrackViewList& sel)
4698 EditorOrderTimeAxisSorter cmp;
4703 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4706 framepos_t where = 0;
4707 EditPoint ep = _edit_point;
4709 if (Profile->get_mixbus()) {
4710 if (ep == EditAtSelectedMarker) {
4711 ep = EditAtPlayhead;
4715 if (from_outside_canvas && (ep == EditAtMouse)) {
4716 ep = EditAtPlayhead;
4717 } else if (from_context_menu && (ep == EditAtMouse)) {
4718 return canvas_event_sample (&context_click_event, 0, 0);
4721 if (entered_marker) {
4722 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4723 return entered_marker->position();
4726 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4727 ep = EditAtSelectedMarker;
4730 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4731 ep = EditAtPlayhead;
4735 case EditAtPlayhead:
4736 if (_dragging_playhead) {
4737 where = *_control_scroll_target;
4739 where = _session->audible_frame();
4741 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4744 case EditAtSelectedMarker:
4745 if (!selection->markers.empty()) {
4747 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4750 where = loc->start();
4754 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4762 if (!mouse_frame (where, ignored)) {
4763 /* XXX not right but what can we do ? */
4767 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4775 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4777 if (!_session) return;
4779 begin_reversible_command (cmd);
4783 if ((tll = transport_loop_location()) == 0) {
4784 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4785 XMLNode &before = _session->locations()->get_state();
4786 _session->locations()->add (loc, true);
4787 _session->set_auto_loop_location (loc);
4788 XMLNode &after = _session->locations()->get_state();
4789 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4791 XMLNode &before = tll->get_state();
4792 tll->set_hidden (false, this);
4793 tll->set (start, end);
4794 XMLNode &after = tll->get_state();
4795 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4798 commit_reversible_command ();
4802 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4804 if (!_session) return;
4806 begin_reversible_command (cmd);
4810 if ((tpl = transport_punch_location()) == 0) {
4811 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4812 XMLNode &before = _session->locations()->get_state();
4813 _session->locations()->add (loc, true);
4814 _session->set_auto_punch_location (loc);
4815 XMLNode &after = _session->locations()->get_state();
4816 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4818 XMLNode &before = tpl->get_state();
4819 tpl->set_hidden (false, this);
4820 tpl->set (start, end);
4821 XMLNode &after = tpl->get_state();
4822 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4825 commit_reversible_command ();
4828 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4829 * @param rs List to which found regions are added.
4830 * @param where Time to look at.
4831 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4834 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4836 const TrackViewList* tracks;
4839 tracks = &track_views;
4844 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4846 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4849 boost::shared_ptr<Track> tr;
4850 boost::shared_ptr<Playlist> pl;
4852 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4854 boost::shared_ptr<RegionList> regions = pl->regions_at (
4855 (framepos_t) floor ( (double) where * tr->speed()));
4857 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4858 RegionView* rv = rtv->view()->find_view (*i);
4869 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4871 const TrackViewList* tracks;
4874 tracks = &track_views;
4879 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4880 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4882 boost::shared_ptr<Track> tr;
4883 boost::shared_ptr<Playlist> pl;
4885 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4887 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4888 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4890 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4892 RegionView* rv = rtv->view()->find_view (*i);
4903 /** Get regions using the following method:
4905 * Make a region list using:
4906 * (a) any selected regions
4907 * (b) the intersection of any selected tracks and the edit point(*)
4908 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4910 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4912 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4916 Editor::get_regions_from_selection_and_edit_point ()
4918 RegionSelection regions;
4920 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4921 regions.add (entered_regionview);
4923 regions = selection->regions;
4926 if ( regions.empty() ) {
4927 TrackViewList tracks = selection->tracks;
4929 if (!tracks.empty()) {
4930 /* no region selected or entered, but some selected tracks:
4931 * act on all regions on the selected tracks at the edit point
4933 framepos_t const where = get_preferred_edit_position ();
4934 get_regions_at(regions, where, tracks);
4941 /** Get regions using the following method:
4943 * Make a region list using:
4944 * (a) any selected regions
4945 * (b) the intersection of any selected tracks and the edit point(*)
4946 * (c) if neither exists, then whatever region is under the mouse
4948 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4950 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4953 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4955 RegionSelection regions;
4957 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4958 regions.add (entered_regionview);
4960 regions = selection->regions;
4963 if ( regions.empty() ) {
4964 TrackViewList tracks = selection->tracks;
4966 if (!tracks.empty()) {
4967 /* no region selected or entered, but some selected tracks:
4968 * act on all regions on the selected tracks at the edit point
4970 get_regions_at(regions, pos, tracks);
4977 /** Start with regions that are selected, or the entered regionview if none are selected.
4978 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4979 * of the regions that we started with.
4983 Editor::get_regions_from_selection_and_entered () const
4985 RegionSelection regions = selection->regions;
4987 if (regions.empty() && entered_regionview) {
4988 regions.add (entered_regionview);
4995 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4997 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4998 RouteTimeAxisView* rtav;
5000 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5001 boost::shared_ptr<Playlist> pl;
5002 std::vector<boost::shared_ptr<Region> > results;
5003 boost::shared_ptr<Track> tr;
5005 if ((tr = rtav->track()) == 0) {
5010 if ((pl = (tr->playlist())) != 0) {
5011 boost::shared_ptr<Region> r = pl->region_by_id (id);
5013 RegionView* rv = rtav->view()->find_view (r);
5015 regions.push_back (rv);
5024 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5027 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5028 MidiTimeAxisView* mtav;
5030 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5032 mtav->get_per_region_note_selection (selection);
5039 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5041 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5043 RouteTimeAxisView* tatv;
5045 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5047 boost::shared_ptr<Playlist> pl;
5048 vector<boost::shared_ptr<Region> > results;
5050 boost::shared_ptr<Track> tr;
5052 if ((tr = tatv->track()) == 0) {
5057 if ((pl = (tr->playlist())) != 0) {
5058 if (src_comparison) {
5059 pl->get_source_equivalent_regions (region, results);
5061 pl->get_region_list_equivalent_regions (region, results);
5065 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5066 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5067 regions.push_back (marv);
5076 Editor::show_rhythm_ferret ()
5078 if (rhythm_ferret == 0) {
5079 rhythm_ferret = new RhythmFerret(*this);
5082 rhythm_ferret->set_session (_session);
5083 rhythm_ferret->show ();
5084 rhythm_ferret->present ();
5088 Editor::first_idle ()
5090 MessageDialog* dialog = 0;
5092 if (track_views.size() > 1) {
5093 Timers::TimerSuspender t;
5094 dialog = new MessageDialog (
5095 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5099 ARDOUR_UI::instance()->flush_pending (60);
5102 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5106 // first idle adds route children (automation tracks), so we need to redisplay here
5107 _routes->redisplay ();
5111 if (_session->undo_depth() == 0) {
5112 undo_action->set_sensitive(false);
5114 redo_action->set_sensitive(false);
5115 begin_selection_op_history ();
5121 Editor::_idle_resize (gpointer arg)
5123 return ((Editor*)arg)->idle_resize ();
5127 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5129 if (resize_idle_id < 0) {
5130 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5131 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5132 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5134 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5135 _pending_resize_amount = 0;
5138 /* make a note of the smallest resulting height, so that we can clamp the
5139 lower limit at TimeAxisView::hSmall */
5141 int32_t min_resulting = INT32_MAX;
5143 _pending_resize_amount += h;
5144 _pending_resize_view = view;
5146 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5148 if (selection->tracks.contains (_pending_resize_view)) {
5149 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5150 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5154 if (min_resulting < 0) {
5159 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5160 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5164 /** Handle pending resizing of tracks */
5166 Editor::idle_resize ()
5168 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5170 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5171 selection->tracks.contains (_pending_resize_view)) {
5173 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5174 if (*i != _pending_resize_view) {
5175 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5180 _pending_resize_amount = 0;
5181 _group_tabs->set_dirty ();
5182 resize_idle_id = -1;
5190 ENSURE_GUI_THREAD (*this, &Editor::located);
5193 playhead_cursor->set_position (_session->audible_frame ());
5194 if (_follow_playhead && !_pending_initial_locate) {
5195 reset_x_origin_to_follow_playhead ();
5199 _pending_locate_request = false;
5200 _pending_initial_locate = false;
5204 Editor::region_view_added (RegionView * rv)
5206 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5207 if (rv->region ()->id () == (*pr)) {
5208 selection->add (rv);
5209 selection->regions.pending.erase (pr);
5214 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5216 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5217 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5218 if (rv->region()->id () == (*rnote).first) {
5219 mrv->select_notes ((*rnote).second);
5220 selection->pending_midi_note_selection.erase(rnote);
5226 _summary->set_background_dirty ();
5230 Editor::region_view_removed ()
5232 _summary->set_background_dirty ();
5236 Editor::axis_view_from_stripable (boost::shared_ptr<Stripable> s) const
5238 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5239 if ((*j)->stripable() == s) {
5249 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5253 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5254 TimeAxisView* tv = axis_view_from_stripable (*i);
5264 Editor::suspend_route_redisplay ()
5267 _routes->suspend_redisplay();
5272 Editor::resume_route_redisplay ()
5275 _routes->redisplay(); // queue redisplay
5276 _routes->resume_redisplay();
5281 Editor::add_vcas (VCAList& vlist)
5285 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5286 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5289 add_stripables (sl);
5293 Editor::add_routes (RouteList& rlist)
5297 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5301 add_stripables (sl);
5305 Editor::add_stripables (StripableList& sl)
5307 list<TimeAxisView*> new_views;
5308 boost::shared_ptr<VCA> v;
5309 boost::shared_ptr<Route> r;
5310 TrackViewList new_selection;
5311 bool from_scratch = (track_views.size() == 0);
5313 sl.sort (StripablePresentationInfoSorter());
5315 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5317 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5319 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5321 new_views.push_back (vtv);
5323 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5325 if (r->is_auditioner() || r->is_monitor()) {
5329 RouteTimeAxisView* rtv;
5330 DataType dt = r->input()->default_type();
5332 if (dt == ARDOUR::DataType::AUDIO) {
5333 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5335 } else if (dt == ARDOUR::DataType::MIDI) {
5336 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5339 throw unknown_type();
5342 new_views.push_back (rtv);
5343 track_views.push_back (rtv);
5344 new_selection.push_back (rtv);
5346 rtv->effective_gain_display ();
5348 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5349 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5353 if (new_views.size() > 0) {
5354 _routes->time_axis_views_added (new_views);
5355 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5358 /* note: !new_selection.empty() means that we got some routes rather
5362 if (!from_scratch && !new_selection.empty()) {
5363 selection->tracks.clear();
5364 selection->add (new_selection);
5365 begin_selection_op_history();
5368 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5369 show_editor_mixer (true);
5372 editor_list_button.set_sensitive (true);
5376 Editor::timeaxisview_deleted (TimeAxisView *tv)
5378 if (tv == entered_track) {
5382 if (_session && _session->deletion_in_progress()) {
5383 /* the situation is under control */
5387 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5389 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5391 _routes->route_removed (tv);
5393 TimeAxisView::Children c = tv->get_child_list ();
5394 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5395 if (entered_track == i->get()) {
5400 /* remove it from the list of track views */
5402 TrackViewList::iterator i;
5404 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5405 i = track_views.erase (i);
5408 /* update whatever the current mixer strip is displaying, if revelant */
5410 boost::shared_ptr<Route> route;
5413 route = rtav->route ();
5416 if (current_mixer_strip && current_mixer_strip->route() == route) {
5418 TimeAxisView* next_tv;
5420 if (track_views.empty()) {
5422 } else if (i == track_views.end()) {
5423 next_tv = track_views.front();
5428 // skip VCAs (cannot be selected, n/a in editor-mixer)
5429 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5430 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5431 next_tv = track_views.front();
5433 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5434 /* just in case: no master, only a VCA remains */
5440 set_selected_mixer_strip (*next_tv);
5442 /* make the editor mixer strip go away setting the
5443 * button to inactive (which also unticks the menu option)
5446 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5452 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5454 if (apply_to_selection) {
5455 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5457 TrackSelection::iterator j = i;
5460 hide_track_in_display (*i, false);
5465 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5467 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5468 // this will hide the mixer strip
5469 set_selected_mixer_strip (*tv);
5472 _routes->hide_track_in_display (*tv);
5477 Editor::sync_track_view_list_and_routes ()
5479 track_views = TrackViewList (_routes->views ());
5481 _summary->set_background_dirty();
5482 _group_tabs->set_dirty ();
5484 return false; // do not call again (until needed)
5488 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5490 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5495 /** Find a RouteTimeAxisView by the ID of its route */
5497 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5499 RouteTimeAxisView* v;
5501 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5502 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5503 if(v->route()->id() == id) {
5513 Editor::fit_route_group (RouteGroup *g)
5515 TrackViewList ts = axis_views_from_routes (g->route_list ());
5520 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5522 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5525 _session->cancel_audition ();
5529 if (_session->is_auditioning()) {
5530 _session->cancel_audition ();
5531 if (r == last_audition_region) {
5536 _session->audition_region (r);
5537 last_audition_region = r;
5542 Editor::hide_a_region (boost::shared_ptr<Region> r)
5544 r->set_hidden (true);
5548 Editor::show_a_region (boost::shared_ptr<Region> r)
5550 r->set_hidden (false);
5554 Editor::audition_region_from_region_list ()
5556 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5560 Editor::hide_region_from_region_list ()
5562 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5566 Editor::show_region_in_region_list ()
5568 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5572 Editor::step_edit_status_change (bool yn)
5575 start_step_editing ();
5577 stop_step_editing ();
5582 Editor::start_step_editing ()
5584 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5588 Editor::stop_step_editing ()
5590 step_edit_connection.disconnect ();
5594 Editor::check_step_edit ()
5596 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5597 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5599 mtv->check_step_edit ();
5603 return true; // do it again, till we stop
5607 Editor::scroll_press (Direction dir)
5609 ++_scroll_callbacks;
5611 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5612 /* delay the first auto-repeat */
5618 scroll_backward (1);
5626 scroll_up_one_track ();
5630 scroll_down_one_track ();
5634 /* do hacky auto-repeat */
5635 if (!_scroll_connection.connected ()) {
5637 _scroll_connection = Glib::signal_timeout().connect (
5638 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5641 _scroll_callbacks = 0;
5648 Editor::scroll_release ()
5650 _scroll_connection.disconnect ();
5653 /** Queue a change for the Editor viewport x origin to follow the playhead */
5655 Editor::reset_x_origin_to_follow_playhead ()
5657 framepos_t const frame = playhead_cursor->current_frame ();
5659 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5661 if (_session->transport_speed() < 0) {
5663 if (frame > (current_page_samples() / 2)) {
5664 center_screen (frame-(current_page_samples()/2));
5666 center_screen (current_page_samples()/2);
5673 if (frame < leftmost_frame) {
5675 if (_session->transport_rolling()) {
5676 /* rolling; end up with the playhead at the right of the page */
5677 l = frame - current_page_samples ();
5679 /* not rolling: end up with the playhead 1/4 of the way along the page */
5680 l = frame - current_page_samples() / 4;
5684 if (_session->transport_rolling()) {
5685 /* rolling: end up with the playhead on the left of the page */
5688 /* not rolling: end up with the playhead 3/4 of the way along the page */
5689 l = frame - 3 * current_page_samples() / 4;
5697 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5703 Editor::super_rapid_screen_update ()
5705 if (!_session || !_session->engine().running()) {
5709 /* METERING / MIXER STRIPS */
5711 /* update track meters, if required */
5712 if (contents().is_mapped() && meters_running) {
5713 RouteTimeAxisView* rtv;
5714 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5715 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5716 rtv->fast_update ();
5721 /* and any current mixer strip */
5722 if (current_mixer_strip) {
5723 current_mixer_strip->fast_update ();
5726 /* PLAYHEAD AND VIEWPORT */
5728 framepos_t const frame = _session->audible_frame();
5730 /* There are a few reasons why we might not update the playhead / viewport stuff:
5732 * 1. we don't update things when there's a pending locate request, otherwise
5733 * when the editor requests a locate there is a chance that this method
5734 * will move the playhead before the locate request is processed, causing
5736 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5737 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5740 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5742 last_update_frame = frame;
5744 if (!_dragging_playhead) {
5745 playhead_cursor->set_position (frame);
5748 if (!_stationary_playhead) {
5750 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5751 /* We only do this if we aren't already
5752 handling a visual change (ie if
5753 pending_visual_change.being_handled is
5754 false) so that these requests don't stack
5755 up there are too many of them to handle in
5758 reset_x_origin_to_follow_playhead ();
5763 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5764 framepos_t const frame = playhead_cursor->current_frame ();
5765 double target = ((double)frame - (double)current_page_samples()/2.0);
5766 if (target <= 0.0) {
5769 // compare to EditorCursor::set_position()
5770 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5771 double const new_pos = sample_to_pixel_unrounded (target);
5772 if (rint (new_pos) != rint (old_pos)) {
5773 reset_x_origin (pixel_to_sample (floor (new_pos)));
5784 Editor::session_going_away ()
5786 _have_idled = false;
5788 _session_connections.drop_connections ();
5790 super_rapid_screen_update_connection.disconnect ();
5792 selection->clear ();
5793 cut_buffer->clear ();
5795 clicked_regionview = 0;
5796 clicked_axisview = 0;
5797 clicked_routeview = 0;
5798 entered_regionview = 0;
5800 last_update_frame = 0;
5803 playhead_cursor->hide ();
5805 /* rip everything out of the list displays */
5809 _route_groups->clear ();
5811 /* do this first so that deleting a track doesn't reset cms to null
5812 and thus cause a leak.
5815 if (current_mixer_strip) {
5816 if (current_mixer_strip->get_parent() != 0) {
5817 global_hpacker.remove (*current_mixer_strip);
5819 delete current_mixer_strip;
5820 current_mixer_strip = 0;
5823 /* delete all trackviews */
5825 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5828 track_views.clear ();
5830 nudge_clock->set_session (0);
5832 editor_list_button.set_active(false);
5833 editor_list_button.set_sensitive(false);
5835 /* clear tempo/meter rulers */
5836 remove_metric_marks ();
5838 clear_marker_display ();
5840 stop_step_editing ();
5844 /* get rid of any existing editor mixer strip */
5846 WindowTitle title(Glib::get_application_name());
5847 title += _("Editor");
5849 own_window()->set_title (title.get_string());
5852 SessionHandlePtr::session_going_away ();
5856 Editor::trigger_script (int i)
5858 LuaInstance::instance()-> call_action (i);
5862 Editor::set_script_action_name (int i, const std::string& n)
5864 string const a = string_compose (X_("script-action-%1"), i + 1);
5865 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5868 act->set_label (string_compose (_("Unset #%1"), i + 1));
5869 act->set_tooltip (_("no action bound"));
5870 act->set_sensitive (false);
5873 act->set_tooltip (n);
5874 act->set_sensitive (true);
5876 KeyEditor::UpdateBindings ();
5880 Editor::show_editor_list (bool yn)
5883 _editor_list_vbox.show ();
5885 _editor_list_vbox.hide ();
5890 Editor::change_region_layering_order (bool from_context_menu)
5892 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5894 if (!clicked_routeview) {
5895 if (layering_order_editor) {
5896 layering_order_editor->hide ();
5901 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5907 boost::shared_ptr<Playlist> pl = track->playlist();
5913 if (layering_order_editor == 0) {
5914 layering_order_editor = new RegionLayeringOrderEditor (*this);
5917 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5918 layering_order_editor->maybe_present ();
5922 Editor::update_region_layering_order_editor ()
5924 if (layering_order_editor && layering_order_editor->is_visible ()) {
5925 change_region_layering_order (true);
5930 Editor::setup_fade_images ()
5932 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5933 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5934 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5935 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5936 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5938 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5939 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5940 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5941 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5942 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5946 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5948 Editor::action_menu_item (std::string const & name)
5950 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5953 return *manage (a->create_menu_item ());
5957 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5959 EventBox* b = manage (new EventBox);
5960 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5961 Label* l = manage (new Label (name));
5965 _the_notebook.append_page (widget, *b);
5969 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5971 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5972 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5975 if (ev->type == GDK_2BUTTON_PRESS) {
5977 /* double-click on a notebook tab shrinks or expands the notebook */
5979 if (_notebook_shrunk) {
5980 if (pre_notebook_shrink_pane_width) {
5981 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
5983 _notebook_shrunk = false;
5985 pre_notebook_shrink_pane_width = edit_pane.get_divider();
5987 /* this expands the LHS of the edit pane to cover the notebook
5988 PAGE but leaves the tabs visible.
5990 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
5991 _notebook_shrunk = true;
5999 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6001 using namespace Menu_Helpers;
6003 MenuList& items = _control_point_context_menu.items ();
6006 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6007 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6008 if (!can_remove_control_point (item)) {
6009 items.back().set_sensitive (false);
6012 _control_point_context_menu.popup (event->button.button, event->button.time);
6016 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6018 using namespace Menu_Helpers;
6020 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6025 /* We need to get the selection here and pass it to the operations, since
6026 popping up the menu will cause a region leave event which clears
6027 entered_regionview. */
6029 MidiRegionView& mrv = note->region_view();
6030 const RegionSelection rs = get_regions_from_selection_and_entered ();
6031 const uint32_t sel_size = mrv.selection_size ();
6033 MenuList& items = _note_context_menu.items();
6037 items.push_back(MenuElem(_("Delete"),
6038 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6041 items.push_back(MenuElem(_("Edit..."),
6042 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6043 if (sel_size != 1) {
6044 items.back().set_sensitive (false);
6047 items.push_back(MenuElem(_("Transpose..."),
6048 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6051 items.push_back(MenuElem(_("Legatize"),
6052 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6054 items.back().set_sensitive (false);
6057 items.push_back(MenuElem(_("Quantize..."),
6058 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6060 items.push_back(MenuElem(_("Remove Overlap"),
6061 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6063 items.back().set_sensitive (false);
6066 items.push_back(MenuElem(_("Transform..."),
6067 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6069 _note_context_menu.popup (event->button.button, event->button.time);
6073 Editor::zoom_vertical_modifier_released()
6075 _stepping_axis_view = 0;
6079 Editor::ui_parameter_changed (string parameter)
6081 if (parameter == "icon-set") {
6082 while (!_cursor_stack.empty()) {
6083 _cursor_stack.pop_back();
6085 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6086 _cursor_stack.push_back(_cursors->grabber);
6087 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6088 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6090 } else if (parameter == "draggable-playhead") {
6091 if (_verbose_cursor) {
6092 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6098 Editor::use_own_window (bool and_fill_it)
6100 bool new_window = !own_window();
6102 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6104 if (win && new_window) {
6105 win->set_name ("EditorWindow");
6107 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6109 // win->signal_realize().connect (*this, &Editor::on_realize);
6110 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6111 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6112 win->set_data ("ardour-bindings", bindings);
6117 DisplaySuspender ds;
6118 contents().show_all ();
6120 /* XXX: this is a bit unfortunate; it would probably
6121 be nicer if we could just call show () above rather
6122 than needing the show_all ()
6125 /* re-hide stuff if necessary */
6126 editor_list_button_toggled ();
6127 parameter_changed ("show-summary");
6128 parameter_changed ("show-group-tabs");
6129 parameter_changed ("show-zoom-tools");
6131 /* now reset all audio_time_axis heights, because widgets might need
6137 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6138 tv = (static_cast<TimeAxisView*>(*i));
6139 tv->reset_height ();
6142 if (current_mixer_strip) {
6143 current_mixer_strip->hide_things ();
6144 current_mixer_strip->parameter_changed ("mixer-element-visibility");