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));
582 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
584 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
585 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
587 edit_controls_vbox.set_spacing (0);
588 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
589 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
591 HBox* h = manage (new HBox);
592 _group_tabs = new EditorGroupTabs (this);
593 if (!ARDOUR::Profile->get_trx()) {
594 h->pack_start (*_group_tabs, PACK_SHRINK);
596 h->pack_start (edit_controls_vbox);
597 controls_layout.add (*h);
599 controls_layout.set_name ("EditControlsBase");
600 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
601 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
602 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
604 _cursors = new MouseCursors;
605 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
606 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
608 /* Push default cursor to ever-present bottom of cursor stack. */
609 push_canvas_cursor(_cursors->grabber);
611 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
613 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
614 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
615 pad_line_1->set_outline_color (0xFF0000FF);
621 edit_packer.set_col_spacings (0);
622 edit_packer.set_row_spacings (0);
623 edit_packer.set_homogeneous (false);
624 edit_packer.set_border_width (0);
625 edit_packer.set_name ("EditorWindow");
627 time_bars_event_box.add (time_bars_vbox);
628 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
629 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
631 /* labels for the time bars */
632 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
634 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
636 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
638 bottom_hbox.set_border_width (2);
639 bottom_hbox.set_spacing (3);
641 _route_groups = new EditorRouteGroups (this);
642 _routes = new EditorRoutes (this);
643 _regions = new EditorRegions (this);
644 _snapshots = new EditorSnapshots (this);
645 _locations = new EditorLocations (this);
646 _time_info_box = new TimeInfoBox (true);
648 /* these are static location signals */
650 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
651 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
652 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
654 add_notebook_page (_("Regions"), _regions->widget ());
655 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
656 add_notebook_page (_("Snapshots"), _snapshots->widget ());
657 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
658 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
660 _the_notebook.set_show_tabs (true);
661 _the_notebook.set_scrollable (true);
662 _the_notebook.popup_disable ();
663 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
664 _the_notebook.show_all ();
666 _notebook_shrunk = false;
669 /* Pick up some settings we need to cache, early */
671 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
674 if (settings && (prop = settings->property ("notebook-shrunk"))) {
675 _notebook_shrunk = string_is_affirmative (prop->value ());
678 editor_summary_pane.set_check_divider_position (true);
679 editor_summary_pane.add (edit_packer);
681 Button* summary_arrows_left_left = manage (new Button);
682 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
683 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
684 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
686 Button* summary_arrows_left_right = manage (new Button);
687 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
688 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
689 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
691 VBox* summary_arrows_left = manage (new VBox);
692 summary_arrows_left->pack_start (*summary_arrows_left_left);
693 summary_arrows_left->pack_start (*summary_arrows_left_right);
695 Button* summary_arrows_right_up = manage (new Button);
696 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
697 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
698 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
700 Button* summary_arrows_right_down = manage (new Button);
701 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
702 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
703 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
705 VBox* summary_arrows_right = manage (new VBox);
706 summary_arrows_right->pack_start (*summary_arrows_right_up);
707 summary_arrows_right->pack_start (*summary_arrows_right_down);
709 Frame* summary_frame = manage (new Frame);
710 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
712 summary_frame->add (*_summary);
713 summary_frame->show ();
715 _summary_hbox.pack_start (*summary_arrows_left, false, false);
716 _summary_hbox.pack_start (*summary_frame, true, true);
717 _summary_hbox.pack_start (*summary_arrows_right, false, false);
719 if (!ARDOUR::Profile->get_trx()) {
720 editor_summary_pane.add (_summary_hbox);
723 edit_pane.set_check_divider_position (true);
724 edit_pane.add (editor_summary_pane);
725 if (!ARDOUR::Profile->get_trx()) {
726 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
727 _editor_list_vbox.pack_start (_the_notebook);
728 edit_pane.add (_editor_list_vbox);
729 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
732 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
733 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
740 if (!settings || ((prop = settings->property ("edit-horizontal-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
741 /* initial allocation is 90% to canvas, 10% to notebook */
742 edit_pane.set_divider (0, 0.90);
744 edit_pane.set_divider (0, fract);
747 if (!settings || ((prop = settings->property ("edit-vertical-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
748 /* initial allocation is 90% to canvas, 10% to summary */
749 editor_summary_pane.set_divider (0, 0.90);
752 editor_summary_pane.set_divider (0, fract);
756 global_vpacker.set_spacing (2);
757 global_vpacker.set_border_width (0);
759 //the next three EventBoxes provide the ability for their child widgets to have a background color. That is all.
761 Gtk::EventBox* ebox = manage (new Gtk::EventBox); //a themeable box
762 ebox->set_name("EditorWindow");
763 ebox->add (toolbar_hbox);
765 Gtk::EventBox* epane_box = manage (new Gtk::EventBox); //a themeable box
766 epane_box->set_name("EditorWindow");
767 epane_box->add (edit_pane);
769 Gtk::EventBox* epane_box2 = manage (new Gtk::EventBox); //a themeable box
770 epane_box2->set_name("EditorWindow");
771 epane_box2->add (global_vpacker);
773 global_vpacker.pack_start (*ebox, false, false);
774 global_vpacker.pack_start (*epane_box, true, true);
775 global_hpacker.pack_start (*epane_box2, true, true);
777 /* need to show the "contents" widget so that notebook will show if tab is switched to
780 global_hpacker.show ();
782 /* register actions now so that set_state() can find them and set toggles/checks etc */
789 _playlist_selector = new PlaylistSelector();
790 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
792 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
796 nudge_forward_button.set_name ("nudge button");
797 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
799 nudge_backward_button.set_name ("nudge button");
800 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
802 fade_context_menu.set_name ("ArdourContextMenu");
804 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
806 /* allow external control surfaces/protocols to do various things */
808 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
809 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
810 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
811 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
812 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
813 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
814 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
815 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
816 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
817 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
818 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
819 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
820 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
821 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
823 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
824 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
825 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
826 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
827 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
829 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
831 PresentationInfo::Change.connect (*this, invalidator (*this), boost::bind (&Editor::presentation_info_changed, this, _1), gui_context());
835 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
837 /* problematic: has to return a value and thus cannot be x-thread */
839 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
841 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
842 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
844 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
846 _ignore_region_action = false;
847 _last_region_menu_was_main = false;
848 _popup_region_menu_item = 0;
850 _show_marker_lines = false;
852 /* Button bindings */
854 button_bindings = new Bindings ("editor-mouse");
856 XMLNode* node = button_settings();
858 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
859 button_bindings->load_operation (**i);
865 /* grab current parameter state */
866 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
867 UIConfiguration::instance().map_parameters (pc);
869 setup_fade_images ();
871 LuaInstance::instance(); // instantiate
872 LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &Editor::set_script_action_name));
879 delete button_bindings;
881 delete _route_groups;
882 delete _track_canvas_viewport;
885 delete _verbose_cursor;
886 delete quantize_dialog;
892 delete _playlist_selector;
893 delete _time_info_box;
898 LuaInstance::destroy_instance ();
900 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
903 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_in_images.begin(); i != _xfade_in_images.end (); ++i) {
906 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_out_images.begin(); i != _xfade_out_images.end (); ++i) {
912 Editor::presentation_info_changed (PropertyChange const & what_changed)
914 if (what_changed.contains (Properties::selected)) {
915 track_selection_changed ();
920 Editor::button_settings () const
922 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
923 XMLNode* node = find_named_node (*settings, X_("Buttons"));
926 node = new XMLNode (X_("Buttons"));
933 Editor::get_smart_mode () const
935 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
939 Editor::catch_vanishing_regionview (RegionView *rv)
941 /* note: the selection will take care of the vanishing
942 audioregionview by itself.
945 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
949 if (clicked_regionview == rv) {
950 clicked_regionview = 0;
953 if (entered_regionview == rv) {
954 set_entered_regionview (0);
957 if (!_all_region_actions_sensitized) {
958 sensitize_all_region_actions (true);
963 Editor::set_entered_regionview (RegionView* rv)
965 if (rv == entered_regionview) {
969 if (entered_regionview) {
970 entered_regionview->exited ();
973 entered_regionview = rv;
975 if (entered_regionview != 0) {
976 entered_regionview->entered ();
979 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
980 /* This RegionView entry might have changed what region actions
981 are allowed, so sensitize them all in case a key is pressed.
983 sensitize_all_region_actions (true);
988 Editor::set_entered_track (TimeAxisView* tav)
991 entered_track->exited ();
997 entered_track->entered ();
1002 Editor::instant_save ()
1004 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
1009 _session->add_instant_xml(get_state());
1011 Config->add_instant_xml(get_state());
1016 Editor::control_vertical_zoom_in_all ()
1018 tav_zoom_smooth (false, true);
1022 Editor::control_vertical_zoom_out_all ()
1024 tav_zoom_smooth (true, true);
1028 Editor::control_vertical_zoom_in_selected ()
1030 tav_zoom_smooth (false, false);
1034 Editor::control_vertical_zoom_out_selected ()
1036 tav_zoom_smooth (true, false);
1040 Editor::control_view (uint32_t view)
1042 goto_visual_state (view);
1046 Editor::control_unselect ()
1048 selection->clear_tracks ();
1052 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1054 TimeAxisView* tav = axis_view_from_stripable (s);
1058 case Selection::Add:
1059 selection->add (tav);
1061 case Selection::Toggle:
1062 selection->toggle (tav);
1064 case Selection::Extend:
1066 case Selection::Set:
1067 selection->set (tav);
1071 selection->clear_tracks ();
1076 Editor::control_step_tracks_up ()
1078 scroll_tracks_up_line ();
1082 Editor::control_step_tracks_down ()
1084 scroll_tracks_down_line ();
1088 Editor::control_scroll (float fraction)
1090 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1096 double step = fraction * current_page_samples();
1099 _control_scroll_target is an optional<T>
1101 it acts like a pointer to an framepos_t, with
1102 a operator conversion to boolean to check
1103 that it has a value could possibly use
1104 playhead_cursor->current_frame to store the
1105 value and a boolean in the class to know
1106 when it's out of date
1109 if (!_control_scroll_target) {
1110 _control_scroll_target = _session->transport_frame();
1111 _dragging_playhead = true;
1114 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1115 *_control_scroll_target = 0;
1116 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1117 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1119 *_control_scroll_target += (framepos_t) trunc (step);
1122 /* move visuals, we'll catch up with it later */
1124 playhead_cursor->set_position (*_control_scroll_target);
1125 UpdateAllTransportClocks (*_control_scroll_target);
1127 if (*_control_scroll_target > (current_page_samples() / 2)) {
1128 /* try to center PH in window */
1129 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1135 Now we do a timeout to actually bring the session to the right place
1136 according to the playhead. This is to avoid reading disk buffers on every
1137 call to control_scroll, which is driven by ScrollTimeline and therefore
1138 probably by a control surface wheel which can generate lots of events.
1140 /* cancel the existing timeout */
1142 control_scroll_connection.disconnect ();
1144 /* add the next timeout */
1146 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1150 Editor::deferred_control_scroll (framepos_t /*target*/)
1152 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1153 // reset for next stream
1154 _control_scroll_target = boost::none;
1155 _dragging_playhead = false;
1160 Editor::access_action (std::string action_group, std::string action_item)
1166 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1169 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1177 Editor::on_realize ()
1181 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1182 start_lock_event_timing ();
1187 Editor::start_lock_event_timing ()
1189 /* check if we should lock the GUI every 30 seconds */
1191 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1195 Editor::generic_event_handler (GdkEvent* ev)
1198 case GDK_BUTTON_PRESS:
1199 case GDK_BUTTON_RELEASE:
1200 case GDK_MOTION_NOTIFY:
1202 case GDK_KEY_RELEASE:
1203 if (contents().is_mapped()) {
1204 gettimeofday (&last_event_time, 0);
1208 case GDK_LEAVE_NOTIFY:
1209 switch (ev->crossing.detail) {
1210 case GDK_NOTIFY_UNKNOWN:
1211 case GDK_NOTIFY_INFERIOR:
1212 case GDK_NOTIFY_ANCESTOR:
1214 case GDK_NOTIFY_VIRTUAL:
1215 case GDK_NOTIFY_NONLINEAR:
1216 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1217 /* leaving window, so reset focus, thus ending any and
1218 all text entry operations.
1220 ARDOUR_UI::instance()->reset_focus (&contents());
1233 Editor::lock_timeout_callback ()
1235 struct timeval now, delta;
1237 gettimeofday (&now, 0);
1239 timersub (&now, &last_event_time, &delta);
1241 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1243 /* don't call again. Returning false will effectively
1244 disconnect us from the timer callback.
1246 unlock() will call start_lock_event_timing() to get things
1256 Editor::map_position_change (framepos_t frame)
1258 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1260 if (_session == 0) {
1264 if (_follow_playhead) {
1265 center_screen (frame);
1268 playhead_cursor->set_position (frame);
1272 Editor::center_screen (framepos_t frame)
1274 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1276 /* if we're off the page, then scroll.
1279 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1280 center_screen_internal (frame, page);
1285 Editor::center_screen_internal (framepos_t frame, float page)
1290 frame -= (framepos_t) page;
1295 reset_x_origin (frame);
1300 Editor::update_title ()
1302 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1304 if (!own_window()) {
1309 bool dirty = _session->dirty();
1311 string session_name;
1313 if (_session->snap_name() != _session->name()) {
1314 session_name = _session->snap_name();
1316 session_name = _session->name();
1320 session_name = "*" + session_name;
1323 WindowTitle title(session_name);
1324 title += S_("Window|Editor");
1325 title += Glib::get_application_name();
1326 own_window()->set_title (title.get_string());
1328 /* ::session_going_away() will have taken care of it */
1333 Editor::set_session (Session *t)
1335 SessionHandlePtr::set_session (t);
1341 _playlist_selector->set_session (_session);
1342 nudge_clock->set_session (_session);
1343 _summary->set_session (_session);
1344 _group_tabs->set_session (_session);
1345 _route_groups->set_session (_session);
1346 _regions->set_session (_session);
1347 _snapshots->set_session (_session);
1348 _routes->set_session (_session);
1349 _locations->set_session (_session);
1350 _time_info_box->set_session (_session);
1352 if (rhythm_ferret) {
1353 rhythm_ferret->set_session (_session);
1356 if (analysis_window) {
1357 analysis_window->set_session (_session);
1361 sfbrowser->set_session (_session);
1364 compute_fixed_ruler_scale ();
1366 /* Make sure we have auto loop and auto punch ranges */
1368 Location* loc = _session->locations()->auto_loop_location();
1370 loc->set_name (_("Loop"));
1373 loc = _session->locations()->auto_punch_location();
1376 loc->set_name (_("Punch"));
1379 refresh_location_display ();
1381 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1382 the selected Marker; this needs the LocationMarker list to be available.
1384 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1385 set_state (*node, Stateful::loading_state_version);
1387 /* catch up with the playhead */
1389 _session->request_locate (playhead_cursor->current_frame ());
1390 _pending_initial_locate = true;
1394 /* These signals can all be emitted by a non-GUI thread. Therefore the
1395 handlers for them must not attempt to directly interact with the GUI,
1396 but use PBD::Signal<T>::connect() which accepts an event loop
1397 ("context") where the handler will be asked to run.
1400 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1401 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1402 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1403 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1404 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1405 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1406 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1407 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1408 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1409 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1410 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1411 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1412 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1413 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1414 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1416 playhead_cursor->show ();
1418 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1419 Config->map_parameters (pc);
1420 _session->config.map_parameters (pc);
1422 restore_ruler_visibility ();
1423 //tempo_map_changed (PropertyChange (0));
1424 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1426 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1427 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1430 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1431 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1434 switch (_snap_type) {
1435 case SnapToRegionStart:
1436 case SnapToRegionEnd:
1437 case SnapToRegionSync:
1438 case SnapToRegionBoundary:
1439 build_region_boundary_cache ();
1446 /* catch up on selection of stripables (other selection state is lost
1447 * when a session is closed
1452 _session->get_stripables (sl);
1453 for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
1454 if ((*s)->presentation_info().selected()) {
1455 RouteTimeAxisView* rtav = get_route_view_by_route_id ((*s)->id());
1457 tl.push_back (rtav);
1462 selection->set (tl);
1465 /* register for undo history */
1466 _session->register_with_memento_command_factory(id(), this);
1467 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1469 LuaInstance::instance()->set_session(_session);
1471 start_updating_meters ();
1475 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1477 using namespace Menu_Helpers;
1479 void (Editor::*emf)(FadeShape);
1480 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1483 images = &_xfade_in_images;
1484 emf = &Editor::set_fade_in_shape;
1486 images = &_xfade_out_images;
1487 emf = &Editor::set_fade_out_shape;
1492 _("Linear (for highly correlated material)"),
1493 *(*images)[FadeLinear],
1494 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1498 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1502 _("Constant power"),
1503 *(*images)[FadeConstantPower],
1504 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1507 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1512 *(*images)[FadeSymmetric],
1513 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1517 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1522 *(*images)[FadeSlow],
1523 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1526 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1531 *(*images)[FadeFast],
1532 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1535 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1538 /** Pop up a context menu for when the user clicks on a start crossfade */
1540 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1542 using namespace Menu_Helpers;
1543 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1548 MenuList& items (xfade_in_context_menu.items());
1551 if (arv->audio_region()->fade_in_active()) {
1552 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1554 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1557 items.push_back (SeparatorElem());
1558 fill_xfade_menu (items, true);
1560 xfade_in_context_menu.popup (button, time);
1563 /** Pop up a context menu for when the user clicks on an end crossfade */
1565 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1567 using namespace Menu_Helpers;
1568 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1573 MenuList& items (xfade_out_context_menu.items());
1576 if (arv->audio_region()->fade_out_active()) {
1577 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1579 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1582 items.push_back (SeparatorElem());
1583 fill_xfade_menu (items, false);
1585 xfade_out_context_menu.popup (button, time);
1589 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1591 using namespace Menu_Helpers;
1592 Menu* (Editor::*build_menu_function)();
1595 switch (item_type) {
1597 case RegionViewName:
1598 case RegionViewNameHighlight:
1599 case LeftFrameHandle:
1600 case RightFrameHandle:
1601 if (with_selection) {
1602 build_menu_function = &Editor::build_track_selection_context_menu;
1604 build_menu_function = &Editor::build_track_region_context_menu;
1609 if (with_selection) {
1610 build_menu_function = &Editor::build_track_selection_context_menu;
1612 build_menu_function = &Editor::build_track_context_menu;
1617 if (clicked_routeview->track()) {
1618 build_menu_function = &Editor::build_track_context_menu;
1620 build_menu_function = &Editor::build_track_bus_context_menu;
1625 /* probably shouldn't happen but if it does, we don't care */
1629 menu = (this->*build_menu_function)();
1630 menu->set_name ("ArdourContextMenu");
1632 /* now handle specific situations */
1634 switch (item_type) {
1636 case RegionViewName:
1637 case RegionViewNameHighlight:
1638 case LeftFrameHandle:
1639 case RightFrameHandle:
1640 if (!with_selection) {
1641 if (region_edit_menu_split_item) {
1642 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1643 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1645 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1648 if (region_edit_menu_split_multichannel_item) {
1649 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1650 region_edit_menu_split_multichannel_item->set_sensitive (true);
1652 region_edit_menu_split_multichannel_item->set_sensitive (false);
1665 /* probably shouldn't happen but if it does, we don't care */
1669 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1671 /* Bounce to disk */
1673 using namespace Menu_Helpers;
1674 MenuList& edit_items = menu->items();
1676 edit_items.push_back (SeparatorElem());
1678 switch (clicked_routeview->audio_track()->freeze_state()) {
1679 case AudioTrack::NoFreeze:
1680 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1683 case AudioTrack::Frozen:
1684 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1687 case AudioTrack::UnFrozen:
1688 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1694 if (item_type == StreamItem && clicked_routeview) {
1695 clicked_routeview->build_underlay_menu(menu);
1698 /* When the region menu is opened, we setup the actions so that they look right
1701 sensitize_the_right_region_actions (false);
1702 _last_region_menu_was_main = false;
1704 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1705 menu->popup (button, time);
1709 Editor::build_track_context_menu ()
1711 using namespace Menu_Helpers;
1713 MenuList& edit_items = track_context_menu.items();
1716 add_dstream_context_items (edit_items);
1717 return &track_context_menu;
1721 Editor::build_track_bus_context_menu ()
1723 using namespace Menu_Helpers;
1725 MenuList& edit_items = track_context_menu.items();
1728 add_bus_context_items (edit_items);
1729 return &track_context_menu;
1733 Editor::build_track_region_context_menu ()
1735 using namespace Menu_Helpers;
1736 MenuList& edit_items = track_region_context_menu.items();
1739 /* we've just cleared the track region context menu, so the menu that these
1740 two items were on will have disappeared; stop them dangling.
1742 region_edit_menu_split_item = 0;
1743 region_edit_menu_split_multichannel_item = 0;
1745 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1748 boost::shared_ptr<Track> tr;
1749 boost::shared_ptr<Playlist> pl;
1751 if ((tr = rtv->track())) {
1752 add_region_context_items (edit_items, tr);
1756 add_dstream_context_items (edit_items);
1758 return &track_region_context_menu;
1762 Editor::loudness_analyze_region_selection ()
1767 Selection& s (PublicEditor::instance ().get_selection ());
1768 RegionSelection ars = s.regions;
1769 ARDOUR::AnalysisGraph ag (_session);
1770 framecnt_t total_work = 0;
1772 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1773 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1777 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1780 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1781 total_work += arv->region ()->length ();
1784 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1786 ag.set_total_frames (total_work);
1787 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1790 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1791 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1795 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1799 ag.analyze_region (ar);
1802 if (!ag.canceled ()) {
1803 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1809 Editor::loudness_analyze_range_selection ()
1814 Selection& s (PublicEditor::instance ().get_selection ());
1815 TimeSelection ts = s.time;
1816 ARDOUR::AnalysisGraph ag (_session);
1817 framecnt_t total_work = 0;
1819 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1820 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1824 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1828 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1829 total_work += j->length ();
1833 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1835 ag.set_total_frames (total_work);
1836 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1839 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1840 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1844 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1848 ag.analyze_range (rui->route (), pl, ts);
1851 if (!ag.canceled ()) {
1852 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1858 Editor::spectral_analyze_region_selection ()
1860 if (analysis_window == 0) {
1861 analysis_window = new AnalysisWindow();
1864 analysis_window->set_session(_session);
1866 analysis_window->show_all();
1869 analysis_window->set_regionmode();
1870 analysis_window->analyze();
1872 analysis_window->present();
1876 Editor::spectral_analyze_range_selection()
1878 if (analysis_window == 0) {
1879 analysis_window = new AnalysisWindow();
1882 analysis_window->set_session(_session);
1884 analysis_window->show_all();
1887 analysis_window->set_rangemode();
1888 analysis_window->analyze();
1890 analysis_window->present();
1894 Editor::build_track_selection_context_menu ()
1896 using namespace Menu_Helpers;
1897 MenuList& edit_items = track_selection_context_menu.items();
1898 edit_items.clear ();
1900 add_selection_context_items (edit_items);
1901 // edit_items.push_back (SeparatorElem());
1902 // add_dstream_context_items (edit_items);
1904 return &track_selection_context_menu;
1908 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1910 using namespace Menu_Helpers;
1912 /* OK, stick the region submenu at the top of the list, and then add
1916 RegionSelection rs = get_regions_from_selection_and_entered ();
1918 string::size_type pos = 0;
1919 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1921 /* we have to hack up the region name because "_" has a special
1922 meaning for menu titles.
1925 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1926 menu_item_name.replace (pos, 1, "__");
1930 if (_popup_region_menu_item == 0) {
1931 _popup_region_menu_item = new MenuItem (menu_item_name);
1932 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1933 _popup_region_menu_item->show ();
1935 _popup_region_menu_item->set_label (menu_item_name);
1938 /* No latering allowed in later is higher layering model */
1939 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1940 if (act && Config->get_layer_model() == LaterHigher) {
1941 act->set_sensitive (false);
1943 act->set_sensitive (true);
1946 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1948 edit_items.push_back (*_popup_region_menu_item);
1949 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1950 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1952 edit_items.push_back (SeparatorElem());
1955 /** Add context menu items relevant to selection ranges.
1956 * @param edit_items List to add the items to.
1959 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1961 using namespace Menu_Helpers;
1963 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1964 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1966 edit_items.push_back (SeparatorElem());
1967 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1969 edit_items.push_back (SeparatorElem());
1970 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1971 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1973 edit_items.push_back (SeparatorElem());
1975 edit_items.push_back (
1977 _("Move Range Start to Previous Region Boundary"),
1978 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1982 edit_items.push_back (
1984 _("Move Range Start to Next Region Boundary"),
1985 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1989 edit_items.push_back (
1991 _("Move Range End to Previous Region Boundary"),
1992 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1996 edit_items.push_back (
1998 _("Move Range End to Next Region Boundary"),
1999 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
2003 edit_items.push_back (SeparatorElem());
2004 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
2005 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
2007 edit_items.push_back (SeparatorElem());
2008 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
2010 edit_items.push_back (SeparatorElem());
2011 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
2012 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
2013 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
2015 edit_items.push_back (SeparatorElem());
2016 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
2018 edit_items.push_back (SeparatorElem());
2019 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
2020 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
2022 edit_items.push_back (SeparatorElem());
2023 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
2024 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
2025 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
2026 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
2027 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
2028 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
2029 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2035 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2037 using namespace Menu_Helpers;
2041 Menu *play_menu = manage (new Menu);
2042 MenuList& play_items = play_menu->items();
2043 play_menu->set_name ("ArdourContextMenu");
2045 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2046 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2047 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2048 play_items.push_back (SeparatorElem());
2049 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2051 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2055 Menu *select_menu = manage (new Menu);
2056 MenuList& select_items = select_menu->items();
2057 select_menu->set_name ("ArdourContextMenu");
2059 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2060 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2061 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2062 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2063 select_items.push_back (SeparatorElem());
2064 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2065 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2066 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2067 select_items.push_back (SeparatorElem());
2068 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2069 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2070 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2071 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2072 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2073 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2074 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2076 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2080 Menu *cutnpaste_menu = manage (new Menu);
2081 MenuList& cutnpaste_items = cutnpaste_menu->items();
2082 cutnpaste_menu->set_name ("ArdourContextMenu");
2084 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2085 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2086 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2088 cutnpaste_items.push_back (SeparatorElem());
2090 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2091 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2093 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2095 /* Adding new material */
2097 edit_items.push_back (SeparatorElem());
2098 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2099 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2103 Menu *nudge_menu = manage (new Menu());
2104 MenuList& nudge_items = nudge_menu->items();
2105 nudge_menu->set_name ("ArdourContextMenu");
2107 edit_items.push_back (SeparatorElem());
2108 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2109 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2110 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2111 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2113 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2117 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2119 using namespace Menu_Helpers;
2123 Menu *play_menu = manage (new Menu);
2124 MenuList& play_items = play_menu->items();
2125 play_menu->set_name ("ArdourContextMenu");
2127 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2128 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2129 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2133 Menu *select_menu = manage (new Menu);
2134 MenuList& select_items = select_menu->items();
2135 select_menu->set_name ("ArdourContextMenu");
2137 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2138 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2139 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2140 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2141 select_items.push_back (SeparatorElem());
2142 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2143 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2144 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2145 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2147 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2151 Menu *cutnpaste_menu = manage (new Menu);
2152 MenuList& cutnpaste_items = cutnpaste_menu->items();
2153 cutnpaste_menu->set_name ("ArdourContextMenu");
2155 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2156 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2157 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2159 Menu *nudge_menu = manage (new Menu());
2160 MenuList& nudge_items = nudge_menu->items();
2161 nudge_menu->set_name ("ArdourContextMenu");
2163 edit_items.push_back (SeparatorElem());
2164 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2165 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2166 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2167 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2169 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2173 Editor::snap_type() const
2179 Editor::snap_musical() const
2181 switch (_snap_type) {
2182 case SnapToBeatDiv128:
2183 case SnapToBeatDiv64:
2184 case SnapToBeatDiv32:
2185 case SnapToBeatDiv28:
2186 case SnapToBeatDiv24:
2187 case SnapToBeatDiv20:
2188 case SnapToBeatDiv16:
2189 case SnapToBeatDiv14:
2190 case SnapToBeatDiv12:
2191 case SnapToBeatDiv10:
2192 case SnapToBeatDiv8:
2193 case SnapToBeatDiv7:
2194 case SnapToBeatDiv6:
2195 case SnapToBeatDiv5:
2196 case SnapToBeatDiv4:
2197 case SnapToBeatDiv3:
2198 case SnapToBeatDiv2:
2210 Editor::snap_mode() const
2216 Editor::set_snap_to (SnapType st)
2218 unsigned int snap_ind = (unsigned int)st;
2220 if (internal_editing()) {
2221 internal_snap_type = st;
2223 pre_internal_snap_type = st;
2228 if (snap_ind > snap_type_strings.size() - 1) {
2230 _snap_type = (SnapType)snap_ind;
2233 string str = snap_type_strings[snap_ind];
2235 if (str != snap_type_selector.get_text()) {
2236 snap_type_selector.set_text (str);
2241 switch (_snap_type) {
2242 case SnapToBeatDiv128:
2243 case SnapToBeatDiv64:
2244 case SnapToBeatDiv32:
2245 case SnapToBeatDiv28:
2246 case SnapToBeatDiv24:
2247 case SnapToBeatDiv20:
2248 case SnapToBeatDiv16:
2249 case SnapToBeatDiv14:
2250 case SnapToBeatDiv12:
2251 case SnapToBeatDiv10:
2252 case SnapToBeatDiv8:
2253 case SnapToBeatDiv7:
2254 case SnapToBeatDiv6:
2255 case SnapToBeatDiv5:
2256 case SnapToBeatDiv4:
2257 case SnapToBeatDiv3:
2258 case SnapToBeatDiv2: {
2259 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
2260 update_tempo_based_rulers ();
2264 case SnapToRegionStart:
2265 case SnapToRegionEnd:
2266 case SnapToRegionSync:
2267 case SnapToRegionBoundary:
2268 build_region_boundary_cache ();
2276 redisplay_tempo (false);
2278 SnapChanged (); /* EMIT SIGNAL */
2282 Editor::set_snap_mode (SnapMode mode)
2284 string str = snap_mode_strings[(int)mode];
2286 if (internal_editing()) {
2287 internal_snap_mode = mode;
2289 pre_internal_snap_mode = mode;
2294 if (str != snap_mode_selector.get_text ()) {
2295 snap_mode_selector.set_text (str);
2302 Editor::set_edit_point_preference (EditPoint ep, bool force)
2304 bool changed = (_edit_point != ep);
2307 if (Profile->get_mixbus())
2308 if (ep == EditAtSelectedMarker)
2309 ep = EditAtPlayhead;
2311 string str = edit_point_strings[(int)ep];
2312 if (str != edit_point_selector.get_text ()) {
2313 edit_point_selector.set_text (str);
2316 update_all_enter_cursors();
2318 if (!force && !changed) {
2322 const char* action=NULL;
2324 switch (_edit_point) {
2325 case EditAtPlayhead:
2326 action = "edit-at-playhead";
2328 case EditAtSelectedMarker:
2329 action = "edit-at-marker";
2332 action = "edit-at-mouse";
2336 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2338 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2342 bool in_track_canvas;
2344 if (!mouse_frame (foo, in_track_canvas)) {
2345 in_track_canvas = false;
2348 reset_canvas_action_sensitivity (in_track_canvas);
2349 sensitize_the_right_region_actions (false);
2355 Editor::set_state (const XMLNode& node, int version)
2357 XMLProperty const * prop;
2359 PBD::Unwinder<bool> nsi (no_save_instant, true);
2362 Tabbable::set_state (node, version);
2364 if (_session && (prop = node.property ("playhead"))) {
2366 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2368 playhead_cursor->set_position (pos);
2370 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2371 playhead_cursor->set_position (0);
2374 playhead_cursor->set_position (0);
2377 if ((prop = node.property ("mixer-width"))) {
2378 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2381 if ((prop = node.property ("zoom-focus"))) {
2382 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2384 zoom_focus_selection_done (zoom_focus);
2387 if ((prop = node.property ("zoom"))) {
2388 /* older versions of ardour used floating point samples_per_pixel */
2389 double f = PBD::atof (prop->value());
2390 reset_zoom (llrintf (f));
2392 reset_zoom (samples_per_pixel);
2395 if ((prop = node.property ("visible-track-count"))) {
2396 set_visible_track_count (PBD::atoi (prop->value()));
2399 if ((prop = node.property ("snap-to"))) {
2400 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2401 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2403 set_snap_to (_snap_type);
2406 if ((prop = node.property ("snap-mode"))) {
2407 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2408 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2409 * snap_mode_selection_done() will only mark an already active item as active
2410 * which does not trigger set_text().
2412 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2414 set_snap_mode (_snap_mode);
2417 if ((prop = node.property ("internal-snap-to"))) {
2418 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2421 if ((prop = node.property ("internal-snap-mode"))) {
2422 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2425 if ((prop = node.property ("pre-internal-snap-to"))) {
2426 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2429 if ((prop = node.property ("pre-internal-snap-mode"))) {
2430 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2433 if ((prop = node.property ("mouse-mode"))) {
2434 MouseMode m = str2mousemode(prop->value());
2435 set_mouse_mode (m, true);
2437 set_mouse_mode (MouseObject, true);
2440 if ((prop = node.property ("left-frame")) != 0) {
2442 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2446 reset_x_origin (pos);
2450 if ((prop = node.property ("y-origin")) != 0) {
2451 reset_y_origin (atof (prop->value ()));
2454 if ((prop = node.property ("join-object-range"))) {
2455 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2456 bool yn = string_is_affirmative (prop->value());
2458 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2459 tact->set_active (!yn);
2460 tact->set_active (yn);
2462 set_mouse_mode(mouse_mode, true);
2465 if ((prop = node.property ("edit-point"))) {
2466 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2468 set_edit_point_preference (_edit_point);
2471 if ((prop = node.property ("show-measures"))) {
2472 bool yn = string_is_affirmative (prop->value());
2473 _show_measures = yn;
2476 if ((prop = node.property ("follow-playhead"))) {
2477 bool yn = string_is_affirmative (prop->value());
2478 set_follow_playhead (yn);
2481 if ((prop = node.property ("stationary-playhead"))) {
2482 bool yn = string_is_affirmative (prop->value());
2483 set_stationary_playhead (yn);
2486 if ((prop = node.property ("region-list-sort-type"))) {
2487 RegionListSortType st;
2488 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2491 if ((prop = node.property ("show-editor-mixer"))) {
2493 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2496 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2497 bool yn = string_is_affirmative (prop->value());
2499 /* do it twice to force the change */
2501 tact->set_active (!yn);
2502 tact->set_active (yn);
2505 if ((prop = node.property ("show-editor-list"))) {
2507 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2510 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2511 bool yn = string_is_affirmative (prop->value());
2513 /* do it twice to force the change */
2515 tact->set_active (!yn);
2516 tact->set_active (yn);
2519 if ((prop = node.property (X_("editor-list-page")))) {
2520 _the_notebook.set_current_page (atoi (prop->value ()));
2523 if ((prop = node.property (X_("show-marker-lines")))) {
2524 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2526 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2527 bool yn = string_is_affirmative (prop->value ());
2529 tact->set_active (!yn);
2530 tact->set_active (yn);
2533 XMLNodeList children = node.children ();
2534 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2535 selection->set_state (**i, Stateful::current_state_version);
2536 _regions->set_state (**i);
2537 _locations->set_state (**i);
2540 if ((prop = node.property ("maximised"))) {
2541 bool yn = string_is_affirmative (prop->value());
2542 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2544 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2545 bool fs = tact && tact->get_active();
2547 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2551 if ((prop = node.property ("nudge-clock-value"))) {
2553 sscanf (prop->value().c_str(), "%" PRId64, &f);
2554 nudge_clock->set (f);
2556 nudge_clock->set_mode (AudioClock::Timecode);
2557 nudge_clock->set (_session->frame_rate() * 5, true);
2562 * Not all properties may have been in XML, but
2563 * those that are linked to a private variable may need changing
2568 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2570 yn = _show_measures;
2571 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2572 /* do it twice to force the change */
2573 tact->set_active (!yn);
2574 tact->set_active (yn);
2577 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2578 yn = _follow_playhead;
2580 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2581 if (tact->get_active() != yn) {
2582 tact->set_active (yn);
2586 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2587 yn = _stationary_playhead;
2589 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2590 if (tact->get_active() != yn) {
2591 tact->set_active (yn);
2596 return LuaInstance::instance()->set_state(node);
2600 Editor::get_state ()
2602 XMLNode* node = new XMLNode (X_("Editor"));
2606 id().print (buf, sizeof (buf));
2607 node->add_property ("id", buf);
2609 node->add_child_nocopy (Tabbable::get_state());
2611 snprintf(buf,sizeof(buf), "%f", edit_pane.get_divider ());
2612 node->add_property("edit-horizontal-pane-pos", string(buf));
2613 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2614 snprintf(buf,sizeof(buf), "%f", editor_summary_pane.get_divider());
2615 node->add_property("edit-vertical-pane-pos", string(buf));
2617 maybe_add_mixer_strip_width (*node);
2619 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2621 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2622 node->add_property ("zoom", buf);
2623 node->add_property ("snap-to", enum_2_string (_snap_type));
2624 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2625 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2626 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2627 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2628 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2629 node->add_property ("edit-point", enum_2_string (_edit_point));
2630 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2631 node->add_property ("visible-track-count", buf);
2633 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2634 node->add_property ("playhead", buf);
2635 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2636 node->add_property ("left-frame", buf);
2637 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2638 node->add_property ("y-origin", buf);
2640 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2641 node->add_property ("maximised", _maximised ? "yes" : "no");
2642 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2643 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2644 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2645 node->add_property ("mouse-mode", enum2str(mouse_mode));
2646 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2648 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2650 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2651 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2654 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2656 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2657 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2660 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2661 node->add_property (X_("editor-list-page"), buf);
2663 if (button_bindings) {
2664 XMLNode* bb = new XMLNode (X_("Buttons"));
2665 button_bindings->save (*bb);
2666 node->add_child_nocopy (*bb);
2669 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2671 node->add_child_nocopy (selection->get_state ());
2672 node->add_child_nocopy (_regions->get_state ());
2674 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2675 node->add_property ("nudge-clock-value", buf);
2677 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2678 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2679 node->add_child_nocopy (_locations->get_state ());
2684 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2685 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2687 * @return pair: TimeAxisView that y is over, layer index.
2689 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2690 * in stacked or expanded region display mode, otherwise 0.
2692 std::pair<TimeAxisView *, double>
2693 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2695 if (!trackview_relative_offset) {
2696 y -= _trackview_group->canvas_origin().y;
2700 return std::make_pair ( (TimeAxisView *) 0, 0);
2703 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2705 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2712 return std::make_pair ( (TimeAxisView *) 0, 0);
2715 /** Snap a position to the grid, if appropriate, taking into account current
2716 * grid settings and also the state of any snap modifier keys that may be pressed.
2717 * @param start Position to snap.
2718 * @param event Event to get current key modifier information from, or 0.
2721 Editor::snap_to_with_modifier (MusicFrame& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2723 if (!_session || !event) {
2727 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2728 if (_snap_mode == SnapOff) {
2729 snap_to_internal (start, direction, for_mark);
2731 start.set (start.frame, 0);
2734 if (_snap_mode != SnapOff) {
2735 snap_to_internal (start, direction, for_mark);
2736 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2737 /* SnapOff, but we pressed the snap_delta modifier */
2738 snap_to_internal (start, direction, for_mark);
2740 start.set (start.frame, 0);
2746 Editor::snap_to (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap)
2748 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2749 start.set (start.frame, 0);
2753 snap_to_internal (start, direction, for_mark, ensure_snap);
2757 Editor::timecode_snap_to_internal (MusicFrame& pos, RoundMode direction, bool /*for_mark*/)
2759 framepos_t start = pos.frame;
2760 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2761 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2763 switch (_snap_type) {
2764 case SnapToTimecodeFrame:
2765 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2766 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2767 /* start is already on a whole timecode frame, do nothing */
2768 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2769 start = (framepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2771 start = (framepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2775 case SnapToTimecodeSeconds:
2776 if (_session->config.get_timecode_offset_negative()) {
2777 start += _session->config.get_timecode_offset ();
2779 start -= _session->config.get_timecode_offset ();
2781 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2782 (start % one_timecode_second == 0)) {
2783 /* start is already on a whole second, do nothing */
2784 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2785 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2787 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2790 if (_session->config.get_timecode_offset_negative()) {
2791 start -= _session->config.get_timecode_offset ();
2793 start += _session->config.get_timecode_offset ();
2797 case SnapToTimecodeMinutes:
2798 if (_session->config.get_timecode_offset_negative()) {
2799 start += _session->config.get_timecode_offset ();
2801 start -= _session->config.get_timecode_offset ();
2803 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2804 (start % one_timecode_minute == 0)) {
2805 /* start is already on a whole minute, do nothing */
2806 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2807 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2809 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2811 if (_session->config.get_timecode_offset_negative()) {
2812 start -= _session->config.get_timecode_offset ();
2814 start += _session->config.get_timecode_offset ();
2818 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2819 abort(); /*NOTREACHED*/
2826 Editor::snap_to_internal (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap)
2828 const framepos_t one_second = _session->frame_rate();
2829 const framepos_t one_minute = _session->frame_rate() * 60;
2830 framepos_t presnap = start.frame;
2834 switch (_snap_type) {
2835 case SnapToTimecodeFrame:
2836 case SnapToTimecodeSeconds:
2837 case SnapToTimecodeMinutes:
2838 return timecode_snap_to_internal (start, direction, for_mark);
2841 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2842 start.frame % (one_second/75) == 0) {
2843 /* start is already on a whole CD frame, do nothing */
2844 } else if (((direction == 0) && (start.frame % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2845 start.frame = (framepos_t) ceil ((double) start.frame / (one_second / 75)) * (one_second / 75);
2847 start.frame = (framepos_t) floor ((double) start.frame / (one_second / 75)) * (one_second / 75);
2850 start.set (start.frame, 0);
2855 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2856 start.frame % one_second == 0) {
2857 /* start is already on a whole second, do nothing */
2858 } else if (((direction == 0) && (start.frame % one_second > one_second / 2)) || (direction > 0)) {
2859 start.frame = (framepos_t) ceil ((double) start.frame / one_second) * one_second;
2861 start.frame = (framepos_t) floor ((double) start.frame / one_second) * one_second;
2864 start.set (start.frame, 0);
2869 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2870 start.frame % one_minute == 0) {
2871 /* start is already on a whole minute, do nothing */
2872 } else if (((direction == 0) && (start.frame % one_minute > one_minute / 2)) || (direction > 0)) {
2873 start.frame = (framepos_t) ceil ((double) start.frame / one_minute) * one_minute;
2875 start.frame = (framepos_t) floor ((double) start.frame / one_minute) * one_minute;
2878 start.set (start.frame, 0);
2883 start = _session->tempo_map().round_to_bar (start.frame, direction);
2887 start = _session->tempo_map().round_to_beat (start.frame, direction);
2890 case SnapToBeatDiv128:
2891 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 128, direction);
2893 case SnapToBeatDiv64:
2894 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 64, direction);
2896 case SnapToBeatDiv32:
2897 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 32, direction);
2899 case SnapToBeatDiv28:
2900 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 28, direction);
2902 case SnapToBeatDiv24:
2903 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 24, direction);
2905 case SnapToBeatDiv20:
2906 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 20, direction);
2908 case SnapToBeatDiv16:
2909 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 16, direction);
2911 case SnapToBeatDiv14:
2912 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 14, direction);
2914 case SnapToBeatDiv12:
2915 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 12, direction);
2917 case SnapToBeatDiv10:
2918 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 10, direction);
2920 case SnapToBeatDiv8:
2921 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 8, direction);
2923 case SnapToBeatDiv7:
2924 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 7, direction);
2926 case SnapToBeatDiv6:
2927 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 6, direction);
2929 case SnapToBeatDiv5:
2930 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 5, direction);
2932 case SnapToBeatDiv4:
2933 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 4, direction);
2935 case SnapToBeatDiv3:
2936 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 3, direction);
2938 case SnapToBeatDiv2:
2939 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 2, direction);
2947 _session->locations()->marks_either_side (start.frame, before, after);
2949 if (before == max_framepos && after == max_framepos) {
2950 /* No marks to snap to, so just don't snap */
2952 } else if (before == max_framepos) {
2953 start.frame = after;
2954 } else if (after == max_framepos) {
2955 start.frame = before;
2956 } else if (before != max_framepos && after != max_framepos) {
2957 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2958 start.frame = after;
2959 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2960 start.frame = before;
2961 else if (direction == 0 ) {
2962 if ((start.frame - before) < (after - start.frame)) {
2963 start.frame = before;
2965 start.frame = after;
2970 start.set (start.frame, 0);
2974 case SnapToRegionStart:
2975 case SnapToRegionEnd:
2976 case SnapToRegionSync:
2977 case SnapToRegionBoundary:
2978 if (!region_boundary_cache.empty()) {
2980 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2981 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2983 if (direction > 0) {
2984 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame);
2986 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame);
2989 if (next != region_boundary_cache.begin ()) {
2994 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2995 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2997 if (start.frame > (p + n) / 2) {
3004 start.set (start.frame, 0);
3009 switch (_snap_mode) {
3019 if (presnap > start.frame) {
3020 if (presnap > (start.frame + pixel_to_sample(snap_threshold))) {
3021 start.set (presnap, 0);
3024 } else if (presnap < start.frame) {
3025 if (presnap < (start.frame - pixel_to_sample(snap_threshold))) {
3026 start.set (presnap, 0);
3031 /* handled at entry */
3038 Editor::setup_toolbar ()
3040 HBox* mode_box = manage(new HBox);
3041 mode_box->set_border_width (2);
3042 mode_box->set_spacing(2);
3044 HBox* mouse_mode_box = manage (new HBox);
3045 HBox* mouse_mode_hbox = manage (new HBox);
3046 VBox* mouse_mode_vbox = manage (new VBox);
3047 Alignment* mouse_mode_align = manage (new Alignment);
3049 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3050 mouse_mode_size_group->add_widget (smart_mode_button);
3051 mouse_mode_size_group->add_widget (mouse_move_button);
3052 mouse_mode_size_group->add_widget (mouse_cut_button);
3053 mouse_mode_size_group->add_widget (mouse_select_button);
3054 mouse_mode_size_group->add_widget (mouse_timefx_button);
3055 mouse_mode_size_group->add_widget (mouse_audition_button);
3056 mouse_mode_size_group->add_widget (mouse_draw_button);
3057 mouse_mode_size_group->add_widget (mouse_content_button);
3059 if (!Profile->get_mixbus()) {
3060 mouse_mode_size_group->add_widget (zoom_in_button);
3061 mouse_mode_size_group->add_widget (zoom_out_button);
3062 mouse_mode_size_group->add_widget (zoom_out_full_button);
3063 mouse_mode_size_group->add_widget (zoom_focus_selector);
3064 mouse_mode_size_group->add_widget (tav_shrink_button);
3065 mouse_mode_size_group->add_widget (tav_expand_button);
3067 mouse_mode_size_group->add_widget (zoom_preset_selector);
3068 mouse_mode_size_group->add_widget (visible_tracks_selector);
3071 mouse_mode_size_group->add_widget (snap_type_selector);
3072 mouse_mode_size_group->add_widget (snap_mode_selector);
3074 mouse_mode_size_group->add_widget (edit_point_selector);
3075 mouse_mode_size_group->add_widget (edit_mode_selector);
3077 mouse_mode_size_group->add_widget (*nudge_clock);
3078 mouse_mode_size_group->add_widget (nudge_forward_button);
3079 mouse_mode_size_group->add_widget (nudge_backward_button);
3081 mouse_mode_hbox->set_spacing (2);
3083 if (!ARDOUR::Profile->get_trx()) {
3084 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3087 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3088 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3090 if (!ARDOUR::Profile->get_mixbus()) {
3091 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3094 if (!ARDOUR::Profile->get_trx()) {
3095 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3096 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3097 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3098 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3101 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3103 mouse_mode_align->add (*mouse_mode_vbox);
3104 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3106 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3108 edit_mode_selector.set_name ("mouse mode button");
3110 if (!ARDOUR::Profile->get_trx()) {
3111 mode_box->pack_start (edit_mode_selector, false, false);
3114 mode_box->pack_start (*mouse_mode_box, false, false);
3118 _zoom_box.set_spacing (2);
3119 _zoom_box.set_border_width (2);
3123 zoom_preset_selector.set_name ("zoom button");
3124 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
3126 zoom_in_button.set_name ("zoom button");
3127 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3128 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3129 zoom_in_button.set_related_action (act);
3131 zoom_out_button.set_name ("zoom button");
3132 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3133 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3134 zoom_out_button.set_related_action (act);
3136 zoom_out_full_button.set_name ("zoom button");
3137 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3138 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3139 zoom_out_full_button.set_related_action (act);
3141 zoom_focus_selector.set_name ("zoom button");
3143 if (ARDOUR::Profile->get_mixbus()) {
3144 _zoom_box.pack_start (zoom_preset_selector, false, false);
3145 } else if (ARDOUR::Profile->get_trx()) {
3146 mode_box->pack_start (zoom_out_button, false, false);
3147 mode_box->pack_start (zoom_in_button, false, false);
3149 _zoom_box.pack_start (zoom_out_button, false, false);
3150 _zoom_box.pack_start (zoom_in_button, false, false);
3151 _zoom_box.pack_start (zoom_out_full_button, false, false);
3152 _zoom_box.pack_start (zoom_focus_selector, false, false);
3155 /* Track zoom buttons */
3156 _track_box.set_spacing (2);
3157 _track_box.set_border_width (2);
3159 visible_tracks_selector.set_name ("zoom button");
3160 if (Profile->get_mixbus()) {
3161 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3163 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3166 tav_expand_button.set_name ("zoom button");
3167 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3168 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3169 tav_expand_button.set_related_action (act);
3171 tav_shrink_button.set_name ("zoom button");
3172 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3173 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3174 tav_shrink_button.set_related_action (act);
3176 if (ARDOUR::Profile->get_mixbus()) {
3177 _track_box.pack_start (visible_tracks_selector);
3178 } else if (ARDOUR::Profile->get_trx()) {
3179 _track_box.pack_start (tav_shrink_button);
3180 _track_box.pack_start (tav_expand_button);
3182 _track_box.pack_start (visible_tracks_selector);
3183 _track_box.pack_start (tav_shrink_button);
3184 _track_box.pack_start (tav_expand_button);
3187 snap_box.set_spacing (2);
3188 snap_box.set_border_width (2);
3190 snap_type_selector.set_name ("mouse mode button");
3192 snap_mode_selector.set_name ("mouse mode button");
3194 edit_point_selector.set_name ("mouse mode button");
3196 snap_box.pack_start (snap_mode_selector, false, false);
3197 snap_box.pack_start (snap_type_selector, false, false);
3200 HBox *ep_box = manage (new HBox);
3201 ep_box->set_spacing (2);
3202 ep_box->set_border_width (2);
3204 ep_box->pack_start (edit_point_selector, false, false);
3208 HBox *nudge_box = manage (new HBox);
3209 nudge_box->set_spacing (2);
3210 nudge_box->set_border_width (2);
3212 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3213 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3215 nudge_box->pack_start (nudge_backward_button, false, false);
3216 nudge_box->pack_start (nudge_forward_button, false, false);
3217 nudge_box->pack_start (*nudge_clock, false, false);
3220 /* Pack everything in... */
3222 toolbar_hbox.set_spacing (2);
3223 toolbar_hbox.set_border_width (2);
3225 toolbar_hbox.pack_start (*mode_box, false, false);
3227 if (!ARDOUR::Profile->get_trx()) {
3229 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3231 toolbar_hbox.pack_start (_zoom_box, false, false);
3233 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3235 toolbar_hbox.pack_start (_track_box, false, false);
3237 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3239 toolbar_hbox.pack_start (snap_box, false, false);
3241 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3243 toolbar_hbox.pack_start (*ep_box, false, false);
3245 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3247 toolbar_hbox.pack_start (*nudge_box, false, false);
3250 toolbar_hbox.show_all ();
3254 Editor::build_edit_point_menu ()
3256 using namespace Menu_Helpers;
3258 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3259 if(!Profile->get_mixbus())
3260 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3261 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3263 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3267 Editor::build_edit_mode_menu ()
3269 using namespace Menu_Helpers;
3271 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3272 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3273 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3274 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3276 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3280 Editor::build_snap_mode_menu ()
3282 using namespace Menu_Helpers;
3284 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3285 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3286 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3288 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3292 Editor::build_snap_type_menu ()
3294 using namespace Menu_Helpers;
3296 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3297 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3298 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3299 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3300 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3301 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3302 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3303 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3304 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3305 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3306 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3307 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3308 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3309 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3310 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3311 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3312 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3313 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3314 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3315 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3316 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3317 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3318 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3319 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3320 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3321 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3322 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3323 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3324 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3325 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3327 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3332 Editor::setup_tooltips ()
3334 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3335 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3336 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3337 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3338 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3339 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3340 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3341 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3342 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3343 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3344 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3345 set_tooltip (zoom_in_button, _("Zoom In"));
3346 set_tooltip (zoom_out_button, _("Zoom Out"));
3347 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3348 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3349 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3350 set_tooltip (tav_expand_button, _("Expand Tracks"));
3351 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3352 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3353 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3354 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3355 set_tooltip (edit_point_selector, _("Edit Point"));
3356 set_tooltip (edit_mode_selector, _("Edit Mode"));
3357 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3361 Editor::convert_drop_to_paths (
3362 vector<string>& paths,
3363 const RefPtr<Gdk::DragContext>& /*context*/,
3366 const SelectionData& data,
3370 if (_session == 0) {
3374 vector<string> uris = data.get_uris();
3378 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3379 are actually URI lists. So do it by hand.
3382 if (data.get_target() != "text/plain") {
3386 /* Parse the "uri-list" format that Nautilus provides,
3387 where each pathname is delimited by \r\n.
3389 THERE MAY BE NO NULL TERMINATING CHAR!!!
3392 string txt = data.get_text();
3396 p = (char *) malloc (txt.length() + 1);
3397 txt.copy (p, txt.length(), 0);
3398 p[txt.length()] = '\0';
3404 while (g_ascii_isspace (*p))
3408 while (*q && (*q != '\n') && (*q != '\r')) {
3415 while (q > p && g_ascii_isspace (*q))
3420 uris.push_back (string (p, q - p + 1));
3424 p = strchr (p, '\n');
3436 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3437 if ((*i).substr (0,7) == "file://") {
3438 paths.push_back (Glib::filename_from_uri (*i));
3446 Editor::new_tempo_section ()
3451 Editor::map_transport_state ()
3453 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3455 if (_session && _session->transport_stopped()) {
3456 have_pending_keyboard_selection = false;
3459 update_loop_range_view ();
3465 Editor::begin_selection_op_history ()
3467 selection_op_cmd_depth = 0;
3468 selection_op_history_it = 0;
3470 while(!selection_op_history.empty()) {
3471 delete selection_op_history.front();
3472 selection_op_history.pop_front();
3475 selection_undo_action->set_sensitive (false);
3476 selection_redo_action->set_sensitive (false);
3477 selection_op_history.push_front (&_selection_memento->get_state ());
3481 Editor::begin_reversible_selection_op (string name)
3484 //cerr << name << endl;
3485 /* begin/commit pairs can be nested */
3486 selection_op_cmd_depth++;
3491 Editor::commit_reversible_selection_op ()
3494 if (selection_op_cmd_depth == 1) {
3496 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3498 The user has undone some selection ops and then made a new one,
3499 making anything earlier in the list invalid.
3502 list<XMLNode *>::iterator it = selection_op_history.begin();
3503 list<XMLNode *>::iterator e_it = it;
3504 advance (e_it, selection_op_history_it);
3506 for ( ; it != e_it; ++it) {
3509 selection_op_history.erase (selection_op_history.begin(), e_it);
3512 selection_op_history.push_front (&_selection_memento->get_state ());
3513 selection_op_history_it = 0;
3515 selection_undo_action->set_sensitive (true);
3516 selection_redo_action->set_sensitive (false);
3519 if (selection_op_cmd_depth > 0) {
3520 selection_op_cmd_depth--;
3526 Editor::undo_selection_op ()
3529 selection_op_history_it++;
3531 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3532 if (n == selection_op_history_it) {
3533 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3534 selection_redo_action->set_sensitive (true);
3538 /* is there an earlier entry? */
3539 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3540 selection_undo_action->set_sensitive (false);
3546 Editor::redo_selection_op ()
3549 if (selection_op_history_it > 0) {
3550 selection_op_history_it--;
3553 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3554 if (n == selection_op_history_it) {
3555 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3556 selection_undo_action->set_sensitive (true);
3561 if (selection_op_history_it == 0) {
3562 selection_redo_action->set_sensitive (false);
3568 Editor::begin_reversible_command (string name)
3571 before.push_back (&_selection_memento->get_state ());
3572 _session->begin_reversible_command (name);
3577 Editor::begin_reversible_command (GQuark q)
3580 before.push_back (&_selection_memento->get_state ());
3581 _session->begin_reversible_command (q);
3586 Editor::abort_reversible_command ()
3589 while(!before.empty()) {
3590 delete before.front();
3593 _session->abort_reversible_command ();
3598 Editor::commit_reversible_command ()
3601 if (before.size() == 1) {
3602 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3603 redo_action->set_sensitive(false);
3604 undo_action->set_sensitive(true);
3605 begin_selection_op_history ();
3608 if (before.empty()) {
3609 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3614 _session->commit_reversible_command ();
3619 Editor::history_changed ()
3623 if (undo_action && _session) {
3624 if (_session->undo_depth() == 0) {
3625 label = S_("Command|Undo");
3627 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3629 undo_action->property_label() = label;
3632 if (redo_action && _session) {
3633 if (_session->redo_depth() == 0) {
3635 redo_action->set_sensitive (false);
3637 label = string_compose(_("Redo (%1)"), _session->next_redo());
3638 redo_action->set_sensitive (true);
3640 redo_action->property_label() = label;
3645 Editor::duplicate_range (bool with_dialog)
3649 RegionSelection rs = get_regions_from_selection_and_entered ();
3651 if ( selection->time.length() == 0 && rs.empty()) {
3657 ArdourDialog win (_("Duplicate"));
3658 Label label (_("Number of duplications:"));
3659 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3660 SpinButton spinner (adjustment, 0.0, 1);
3663 win.get_vbox()->set_spacing (12);
3664 win.get_vbox()->pack_start (hbox);
3665 hbox.set_border_width (6);
3666 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3668 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3669 place, visually. so do this by hand.
3672 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3673 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3674 spinner.grab_focus();
3680 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3681 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3682 win.set_default_response (RESPONSE_ACCEPT);
3684 spinner.grab_focus ();
3686 switch (win.run ()) {
3687 case RESPONSE_ACCEPT:
3693 times = adjustment.get_value();
3696 if ((current_mouse_mode() == Editing::MouseRange)) {
3697 if (selection->time.length()) {
3698 duplicate_selection (times);
3700 } else if (get_smart_mode()) {
3701 if (selection->time.length()) {
3702 duplicate_selection (times);
3704 duplicate_some_regions (rs, times);
3706 duplicate_some_regions (rs, times);
3711 Editor::set_edit_mode (EditMode m)
3713 Config->set_edit_mode (m);
3717 Editor::cycle_edit_mode ()
3719 switch (Config->get_edit_mode()) {
3721 Config->set_edit_mode (Ripple);
3725 Config->set_edit_mode (Lock);
3728 Config->set_edit_mode (Slide);
3734 Editor::edit_mode_selection_done ( EditMode m )
3736 Config->set_edit_mode ( m );
3740 Editor::snap_type_selection_done (SnapType snaptype)
3742 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3744 ract->set_active ();
3749 Editor::snap_mode_selection_done (SnapMode mode)
3751 RefPtr<RadioAction> ract = snap_mode_action (mode);
3754 ract->set_active (true);
3759 Editor::cycle_edit_point (bool with_marker)
3761 if(Profile->get_mixbus())
3762 with_marker = false;
3764 switch (_edit_point) {
3766 set_edit_point_preference (EditAtPlayhead);
3768 case EditAtPlayhead:
3770 set_edit_point_preference (EditAtSelectedMarker);
3772 set_edit_point_preference (EditAtMouse);
3775 case EditAtSelectedMarker:
3776 set_edit_point_preference (EditAtMouse);
3782 Editor::edit_point_selection_done (EditPoint ep)
3784 set_edit_point_preference ( ep );
3788 Editor::build_zoom_focus_menu ()
3790 using namespace Menu_Helpers;
3792 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3793 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3794 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3795 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3796 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3797 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3799 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3803 Editor::zoom_focus_selection_done ( ZoomFocus f )
3805 RefPtr<RadioAction> ract = zoom_focus_action (f);
3807 ract->set_active ();
3812 Editor::build_track_count_menu ()
3814 using namespace Menu_Helpers;
3816 if (!Profile->get_mixbus()) {
3817 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3818 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3819 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3820 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3821 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3822 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3823 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3824 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3825 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3826 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3827 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3828 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3829 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3831 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3832 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3833 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3834 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3835 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3836 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3837 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3838 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3839 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3840 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3842 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3843 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3844 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3845 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3846 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3847 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3848 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3849 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3850 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3851 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3852 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3857 Editor::set_zoom_preset (int64_t ms)
3860 temporal_zoom_session();
3864 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3865 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3869 Editor::set_visible_track_count (int32_t n)
3871 _visible_track_count = n;
3873 /* if the canvas hasn't really been allocated any size yet, just
3874 record the desired number of visible tracks and return. when canvas
3875 allocation happens, we will get called again and then we can do the
3879 if (_visible_canvas_height <= 1) {
3885 DisplaySuspender ds;
3887 if (_visible_track_count > 0) {
3888 h = trackviews_height() / _visible_track_count;
3889 std::ostringstream s;
3890 s << _visible_track_count;
3892 } else if (_visible_track_count == 0) {
3894 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3895 if ((*i)->marked_for_display()) {
3899 h = trackviews_height() / n;
3902 /* negative value means that the visible track count has
3903 been overridden by explicit track height changes.
3905 visible_tracks_selector.set_text (X_("*"));
3909 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3910 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3913 if (str != visible_tracks_selector.get_text()) {
3914 visible_tracks_selector.set_text (str);
3919 Editor::override_visible_track_count ()
3921 _visible_track_count = -1;
3922 visible_tracks_selector.set_text ( _("*") );
3926 Editor::edit_controls_button_release (GdkEventButton* ev)
3928 if (Keyboard::is_context_menu_event (ev)) {
3929 ARDOUR_UI::instance()->add_route ();
3930 } else if (ev->button == 1) {
3931 selection->clear_tracks ();
3938 Editor::mouse_select_button_release (GdkEventButton* ev)
3940 /* this handles just right-clicks */
3942 if (ev->button != 3) {
3950 Editor::set_zoom_focus (ZoomFocus f)
3952 string str = zoom_focus_strings[(int)f];
3954 if (str != zoom_focus_selector.get_text()) {
3955 zoom_focus_selector.set_text (str);
3958 if (zoom_focus != f) {
3965 Editor::cycle_zoom_focus ()
3967 switch (zoom_focus) {
3969 set_zoom_focus (ZoomFocusRight);
3971 case ZoomFocusRight:
3972 set_zoom_focus (ZoomFocusCenter);
3974 case ZoomFocusCenter:
3975 set_zoom_focus (ZoomFocusPlayhead);
3977 case ZoomFocusPlayhead:
3978 set_zoom_focus (ZoomFocusMouse);
3980 case ZoomFocusMouse:
3981 set_zoom_focus (ZoomFocusEdit);
3984 set_zoom_focus (ZoomFocusLeft);
3990 Editor::set_show_measures (bool yn)
3992 if (_show_measures != yn) {
3995 if ((_show_measures = yn) == true) {
3997 tempo_lines->show();
4000 std::vector<TempoMap::BBTPoint> grid;
4001 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
4002 draw_measures (grid);
4010 Editor::toggle_follow_playhead ()
4012 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
4014 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4015 set_follow_playhead (tact->get_active());
4019 /** @param yn true to follow playhead, otherwise false.
4020 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4023 Editor::set_follow_playhead (bool yn, bool catch_up)
4025 if (_follow_playhead != yn) {
4026 if ((_follow_playhead = yn) == true && catch_up) {
4028 reset_x_origin_to_follow_playhead ();
4035 Editor::toggle_stationary_playhead ()
4037 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4039 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4040 set_stationary_playhead (tact->get_active());
4045 Editor::set_stationary_playhead (bool yn)
4047 if (_stationary_playhead != yn) {
4048 if ((_stationary_playhead = yn) == true) {
4050 // FIXME need a 3.0 equivalent of this 2.X call
4051 // update_current_screen ();
4058 Editor::playlist_selector () const
4060 return *_playlist_selector;
4064 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4066 if (paste_count == 0) {
4067 /* don't bother calculating an offset that will be zero anyway */
4071 /* calculate basic unsnapped multi-paste offset */
4072 framecnt_t offset = paste_count * duration;
4074 /* snap offset so pos + offset is aligned to the grid */
4075 MusicFrame offset_pos (pos + offset, 0);
4076 snap_to(offset_pos, RoundUpMaybe);
4077 offset = offset_pos.frame - pos;
4083 Editor::get_grid_beat_divisions(framepos_t position)
4085 switch (_snap_type) {
4086 case SnapToBeatDiv128: return 128;
4087 case SnapToBeatDiv64: return 64;
4088 case SnapToBeatDiv32: return 32;
4089 case SnapToBeatDiv28: return 28;
4090 case SnapToBeatDiv24: return 24;
4091 case SnapToBeatDiv20: return 20;
4092 case SnapToBeatDiv16: return 16;
4093 case SnapToBeatDiv14: return 14;
4094 case SnapToBeatDiv12: return 12;
4095 case SnapToBeatDiv10: return 10;
4096 case SnapToBeatDiv8: return 8;
4097 case SnapToBeatDiv7: return 7;
4098 case SnapToBeatDiv6: return 6;
4099 case SnapToBeatDiv5: return 5;
4100 case SnapToBeatDiv4: return 4;
4101 case SnapToBeatDiv3: return 3;
4102 case SnapToBeatDiv2: return 2;
4108 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4109 if the grid is non-musical, returns 0.
4110 if the grid is snapped to bars, returns -1.
4111 @param event_state the current keyboard modifier mask.
4114 Editor::get_grid_music_divisions (uint32_t event_state)
4116 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4120 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4124 switch (_snap_type) {
4125 case SnapToBeatDiv128: return 128;
4126 case SnapToBeatDiv64: return 64;
4127 case SnapToBeatDiv32: return 32;
4128 case SnapToBeatDiv28: return 28;
4129 case SnapToBeatDiv24: return 24;
4130 case SnapToBeatDiv20: return 20;
4131 case SnapToBeatDiv16: return 16;
4132 case SnapToBeatDiv14: return 14;
4133 case SnapToBeatDiv12: return 12;
4134 case SnapToBeatDiv10: return 10;
4135 case SnapToBeatDiv8: return 8;
4136 case SnapToBeatDiv7: return 7;
4137 case SnapToBeatDiv6: return 6;
4138 case SnapToBeatDiv5: return 5;
4139 case SnapToBeatDiv4: return 4;
4140 case SnapToBeatDiv3: return 3;
4141 case SnapToBeatDiv2: return 2;
4142 case SnapToBeat: return 1;
4143 case SnapToBar : return -1;
4150 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4154 const unsigned divisions = get_grid_beat_divisions(position);
4156 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4159 switch (_snap_type) {
4161 return Evoral::Beats(4.0 / _session->tempo_map().meter_at_frame (position).note_divisor());
4164 const Meter& m = _session->tempo_map().meter_at_frame (position);
4165 return Evoral::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4173 return Evoral::Beats();
4177 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4181 ret = nudge_clock->current_duration (pos);
4182 next = ret + 1; /* XXXX fix me */
4188 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4190 ArdourDialog dialog (_("Playlist Deletion"));
4191 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4192 "If it is kept, its audio files will not be cleaned.\n"
4193 "If it is deleted, audio files used by it alone will be cleaned."),
4196 dialog.set_position (WIN_POS_CENTER);
4197 dialog.get_vbox()->pack_start (label);
4201 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4202 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4203 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4204 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4205 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4207 // by default gtk uses the left most button
4208 keep->grab_focus ();
4210 switch (dialog.run ()) {
4212 /* keep this and all remaining ones */
4217 /* delete this and all others */
4221 case RESPONSE_ACCEPT:
4222 /* delete the playlist */
4226 case RESPONSE_REJECT:
4227 /* keep the playlist */
4239 Editor::audio_region_selection_covers (framepos_t where)
4241 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4242 if ((*a)->region()->covers (where)) {
4251 Editor::prepare_for_cleanup ()
4253 cut_buffer->clear_regions ();
4254 cut_buffer->clear_playlists ();
4256 selection->clear_regions ();
4257 selection->clear_playlists ();
4259 _regions->suspend_redisplay ();
4263 Editor::finish_cleanup ()
4265 _regions->resume_redisplay ();
4269 Editor::transport_loop_location()
4272 return _session->locations()->auto_loop_location();
4279 Editor::transport_punch_location()
4282 return _session->locations()->auto_punch_location();
4289 Editor::control_layout_scroll (GdkEventScroll* ev)
4291 /* Just forward to the normal canvas scroll method. The coordinate
4292 systems are different but since the canvas is always larger than the
4293 track headers, and aligned with the trackview area, this will work.
4295 In the not too distant future this layout is going away anyway and
4296 headers will be on the canvas.
4298 return canvas_scroll_event (ev, false);
4302 Editor::session_state_saved (string)
4305 _snapshots->redisplay ();
4309 Editor::maximise_editing_space ()
4315 Gtk::Window* toplevel = current_toplevel();
4318 toplevel->fullscreen ();
4324 Editor::restore_editing_space ()
4330 Gtk::Window* toplevel = current_toplevel();
4333 toplevel->unfullscreen();
4339 * Make new playlists for a given track and also any others that belong
4340 * to the same active route group with the `select' property.
4345 Editor::new_playlists (TimeAxisView* v)
4347 begin_reversible_command (_("new playlists"));
4348 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4349 _session->playlists->get (playlists);
4350 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4351 commit_reversible_command ();
4355 * Use a copy of the current playlist for a given track and also any others that belong
4356 * to the same active route group with the `select' property.
4361 Editor::copy_playlists (TimeAxisView* v)
4363 begin_reversible_command (_("copy playlists"));
4364 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4365 _session->playlists->get (playlists);
4366 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4367 commit_reversible_command ();
4370 /** Clear the current playlist for a given track and also any others that belong
4371 * to the same active route group with the `select' property.
4376 Editor::clear_playlists (TimeAxisView* v)
4378 begin_reversible_command (_("clear playlists"));
4379 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4380 _session->playlists->get (playlists);
4381 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4382 commit_reversible_command ();
4386 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4388 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4392 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4394 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4398 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4400 atv.clear_playlist ();
4404 Editor::get_y_origin () const
4406 return vertical_adjustment.get_value ();
4409 /** Queue up a change to the viewport x origin.
4410 * @param frame New x origin.
4413 Editor::reset_x_origin (framepos_t frame)
4415 pending_visual_change.add (VisualChange::TimeOrigin);
4416 pending_visual_change.time_origin = frame;
4417 ensure_visual_change_idle_handler ();
4421 Editor::reset_y_origin (double y)
4423 pending_visual_change.add (VisualChange::YOrigin);
4424 pending_visual_change.y_origin = y;
4425 ensure_visual_change_idle_handler ();
4429 Editor::reset_zoom (framecnt_t spp)
4431 if (spp == samples_per_pixel) {
4435 pending_visual_change.add (VisualChange::ZoomLevel);
4436 pending_visual_change.samples_per_pixel = spp;
4437 ensure_visual_change_idle_handler ();
4441 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4443 reset_x_origin (frame);
4446 if (!no_save_visual) {
4447 undo_visual_stack.push_back (current_visual_state(false));
4451 Editor::VisualState::VisualState (bool with_tracks)
4452 : gui_state (with_tracks ? new GUIObjectState : 0)
4456 Editor::VisualState::~VisualState ()
4461 Editor::VisualState*
4462 Editor::current_visual_state (bool with_tracks)
4464 VisualState* vs = new VisualState (with_tracks);
4465 vs->y_position = vertical_adjustment.get_value();
4466 vs->samples_per_pixel = samples_per_pixel;
4467 vs->leftmost_frame = leftmost_frame;
4468 vs->zoom_focus = zoom_focus;
4471 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4478 Editor::undo_visual_state ()
4480 if (undo_visual_stack.empty()) {
4484 VisualState* vs = undo_visual_stack.back();
4485 undo_visual_stack.pop_back();
4488 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4491 use_visual_state (*vs);
4496 Editor::redo_visual_state ()
4498 if (redo_visual_stack.empty()) {
4502 VisualState* vs = redo_visual_stack.back();
4503 redo_visual_stack.pop_back();
4505 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4506 // why do we check here?
4507 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4510 use_visual_state (*vs);
4515 Editor::swap_visual_state ()
4517 if (undo_visual_stack.empty()) {
4518 redo_visual_state ();
4520 undo_visual_state ();
4525 Editor::use_visual_state (VisualState& vs)
4527 PBD::Unwinder<bool> nsv (no_save_visual, true);
4528 DisplaySuspender ds;
4530 vertical_adjustment.set_value (vs.y_position);
4532 set_zoom_focus (vs.zoom_focus);
4533 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4536 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4538 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4539 (*i)->clear_property_cache();
4540 (*i)->reset_visual_state ();
4544 _routes->update_visibility ();
4547 /** This is the core function that controls the zoom level of the canvas. It is called
4548 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4549 * @param spp new number of samples per pixel
4552 Editor::set_samples_per_pixel (framecnt_t spp)
4558 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4559 const framecnt_t lots_of_pixels = 4000;
4561 /* if the zoom level is greater than what you'd get trying to display 3
4562 * days of audio on a really big screen, then it's too big.
4565 if (spp * lots_of_pixels > three_days) {
4569 samples_per_pixel = spp;
4572 tempo_lines->tempo_map_changed();
4575 bool const showing_time_selection = selection->time.length() > 0;
4577 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4578 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4579 (*i)->reshow_selection (selection->time);
4583 ZoomChanged (); /* EMIT_SIGNAL */
4585 ArdourCanvas::GtkCanvasViewport* c;
4587 c = get_track_canvas();
4589 c->canvas()->zoomed ();
4592 if (playhead_cursor) {
4593 playhead_cursor->set_position (playhead_cursor->current_frame ());
4596 refresh_location_display();
4597 _summary->set_overlays_dirty ();
4599 update_marker_labels ();
4605 Editor::playhead_cursor_sample () const
4607 return playhead_cursor->current_frame();
4611 Editor::queue_visual_videotimeline_update ()
4614 * pending_visual_change.add (VisualChange::VideoTimeline);
4615 * or maybe even more specific: which videotimeline-image
4616 * currently it calls update_video_timeline() to update
4617 * _all outdated_ images on the video-timeline.
4618 * see 'exposeimg()' in video_image_frame.cc
4620 ensure_visual_change_idle_handler ();
4624 Editor::ensure_visual_change_idle_handler ()
4626 if (pending_visual_change.idle_handler_id < 0) {
4627 // see comment in add_to_idle_resize above.
4628 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4629 pending_visual_change.being_handled = false;
4634 Editor::_idle_visual_changer (void* arg)
4636 return static_cast<Editor*>(arg)->idle_visual_changer ();
4640 Editor::idle_visual_changer ()
4642 /* set_horizontal_position() below (and maybe other calls) call
4643 gtk_main_iteration(), so it's possible that a signal will be handled
4644 half-way through this method. If this signal wants an
4645 idle_visual_changer we must schedule another one after this one, so
4646 mark the idle_handler_id as -1 here to allow that. Also make a note
4647 that we are doing the visual change, so that changes in response to
4648 super-rapid-screen-update can be dropped if we are still processing
4652 pending_visual_change.idle_handler_id = -1;
4653 pending_visual_change.being_handled = true;
4655 VisualChange vc = pending_visual_change;
4657 pending_visual_change.pending = (VisualChange::Type) 0;
4659 visual_changer (vc);
4661 pending_visual_change.being_handled = false;
4663 return 0; /* this is always a one-shot call */
4667 Editor::visual_changer (const VisualChange& vc)
4669 double const last_time_origin = horizontal_position ();
4671 if (vc.pending & VisualChange::ZoomLevel) {
4672 set_samples_per_pixel (vc.samples_per_pixel);
4674 compute_fixed_ruler_scale ();
4676 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4677 update_tempo_based_rulers ();
4679 update_video_timeline();
4682 if (vc.pending & VisualChange::TimeOrigin) {
4683 set_horizontal_position (vc.time_origin / samples_per_pixel);
4686 if (vc.pending & VisualChange::YOrigin) {
4687 vertical_adjustment.set_value (vc.y_origin);
4690 if (last_time_origin == horizontal_position ()) {
4691 /* changed signal not emitted */
4692 update_fixed_rulers ();
4693 redisplay_tempo (true);
4696 if (!(vc.pending & VisualChange::ZoomLevel)) {
4697 update_video_timeline();
4700 _summary->set_overlays_dirty ();
4703 struct EditorOrderTimeAxisSorter {
4704 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4705 return a->order () < b->order ();
4710 Editor::sort_track_selection (TrackViewList& sel)
4712 EditorOrderTimeAxisSorter cmp;
4717 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4720 framepos_t where = 0;
4721 EditPoint ep = _edit_point;
4723 if (Profile->get_mixbus()) {
4724 if (ep == EditAtSelectedMarker) {
4725 ep = EditAtPlayhead;
4729 if (from_outside_canvas && (ep == EditAtMouse)) {
4730 ep = EditAtPlayhead;
4731 } else if (from_context_menu && (ep == EditAtMouse)) {
4732 return canvas_event_sample (&context_click_event, 0, 0);
4735 if (entered_marker) {
4736 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4737 return entered_marker->position();
4740 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4741 ep = EditAtSelectedMarker;
4744 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4745 ep = EditAtPlayhead;
4748 MusicFrame snap_mf (0, 0);
4751 case EditAtPlayhead:
4752 if (_dragging_playhead) {
4753 where = *_control_scroll_target;
4755 where = _session->audible_frame();
4757 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4760 case EditAtSelectedMarker:
4761 if (!selection->markers.empty()) {
4763 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4766 where = loc->start();
4770 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4778 if (!mouse_frame (where, ignored)) {
4779 /* XXX not right but what can we do ? */
4782 snap_mf.frame = where;
4784 where = snap_mf.frame;
4785 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4793 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4795 if (!_session) return;
4797 begin_reversible_command (cmd);
4801 if ((tll = transport_loop_location()) == 0) {
4802 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4803 XMLNode &before = _session->locations()->get_state();
4804 _session->locations()->add (loc, true);
4805 _session->set_auto_loop_location (loc);
4806 XMLNode &after = _session->locations()->get_state();
4807 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4809 XMLNode &before = tll->get_state();
4810 tll->set_hidden (false, this);
4811 tll->set (start, end);
4812 XMLNode &after = tll->get_state();
4813 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4816 commit_reversible_command ();
4820 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4822 if (!_session) return;
4824 begin_reversible_command (cmd);
4828 if ((tpl = transport_punch_location()) == 0) {
4829 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4830 XMLNode &before = _session->locations()->get_state();
4831 _session->locations()->add (loc, true);
4832 _session->set_auto_punch_location (loc);
4833 XMLNode &after = _session->locations()->get_state();
4834 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4836 XMLNode &before = tpl->get_state();
4837 tpl->set_hidden (false, this);
4838 tpl->set (start, end);
4839 XMLNode &after = tpl->get_state();
4840 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4843 commit_reversible_command ();
4846 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4847 * @param rs List to which found regions are added.
4848 * @param where Time to look at.
4849 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4852 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4854 const TrackViewList* tracks;
4857 tracks = &track_views;
4862 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4864 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4867 boost::shared_ptr<Track> tr;
4868 boost::shared_ptr<Playlist> pl;
4870 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4872 boost::shared_ptr<RegionList> regions = pl->regions_at (
4873 (framepos_t) floor ( (double) where * tr->speed()));
4875 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4876 RegionView* rv = rtv->view()->find_view (*i);
4887 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4889 const TrackViewList* tracks;
4892 tracks = &track_views;
4897 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4898 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4900 boost::shared_ptr<Track> tr;
4901 boost::shared_ptr<Playlist> pl;
4903 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4905 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4906 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4908 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4910 RegionView* rv = rtv->view()->find_view (*i);
4921 /** Get regions using the following method:
4923 * Make a region list using:
4924 * (a) any selected regions
4925 * (b) the intersection of any selected tracks and the edit point(*)
4926 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4928 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4930 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4934 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4936 RegionSelection regions;
4938 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4939 regions.add (entered_regionview);
4941 regions = selection->regions;
4944 if ( regions.empty() ) {
4945 TrackViewList tracks = selection->tracks;
4947 if (!tracks.empty()) {
4948 /* no region selected or entered, but some selected tracks:
4949 * act on all regions on the selected tracks at the edit point
4951 framepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
4952 get_regions_at(regions, where, tracks);
4959 /** Get regions using the following method:
4961 * Make a region list using:
4962 * (a) any selected regions
4963 * (b) the intersection of any selected tracks and the edit point(*)
4964 * (c) if neither exists, then whatever region is under the mouse
4966 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4968 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4971 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4973 RegionSelection regions;
4975 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4976 regions.add (entered_regionview);
4978 regions = selection->regions;
4981 if ( regions.empty() ) {
4982 TrackViewList tracks = selection->tracks;
4984 if (!tracks.empty()) {
4985 /* no region selected or entered, but some selected tracks:
4986 * act on all regions on the selected tracks at the edit point
4988 get_regions_at(regions, pos, tracks);
4995 /** Start with regions that are selected, or the entered regionview if none are selected.
4996 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4997 * of the regions that we started with.
5001 Editor::get_regions_from_selection_and_entered () const
5003 RegionSelection regions = selection->regions;
5005 if (regions.empty() && entered_regionview) {
5006 regions.add (entered_regionview);
5013 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
5015 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5016 RouteTimeAxisView* rtav;
5018 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5019 boost::shared_ptr<Playlist> pl;
5020 std::vector<boost::shared_ptr<Region> > results;
5021 boost::shared_ptr<Track> tr;
5023 if ((tr = rtav->track()) == 0) {
5028 if ((pl = (tr->playlist())) != 0) {
5029 boost::shared_ptr<Region> r = pl->region_by_id (id);
5031 RegionView* rv = rtav->view()->find_view (r);
5033 regions.push_back (rv);
5042 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5045 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5046 MidiTimeAxisView* mtav;
5048 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5050 mtav->get_per_region_note_selection (selection);
5057 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5059 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5061 RouteTimeAxisView* tatv;
5063 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5065 boost::shared_ptr<Playlist> pl;
5066 vector<boost::shared_ptr<Region> > results;
5068 boost::shared_ptr<Track> tr;
5070 if ((tr = tatv->track()) == 0) {
5075 if ((pl = (tr->playlist())) != 0) {
5076 if (src_comparison) {
5077 pl->get_source_equivalent_regions (region, results);
5079 pl->get_region_list_equivalent_regions (region, results);
5083 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5084 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5085 regions.push_back (marv);
5094 Editor::show_rhythm_ferret ()
5096 if (rhythm_ferret == 0) {
5097 rhythm_ferret = new RhythmFerret(*this);
5100 rhythm_ferret->set_session (_session);
5101 rhythm_ferret->show ();
5102 rhythm_ferret->present ();
5106 Editor::first_idle ()
5108 MessageDialog* dialog = 0;
5110 if (track_views.size() > 1) {
5111 Timers::TimerSuspender t;
5112 dialog = new MessageDialog (
5113 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5117 ARDOUR_UI::instance()->flush_pending (60);
5120 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5124 // first idle adds route children (automation tracks), so we need to redisplay here
5125 _routes->redisplay ();
5129 if (_session->undo_depth() == 0) {
5130 undo_action->set_sensitive(false);
5132 redo_action->set_sensitive(false);
5133 begin_selection_op_history ();
5139 Editor::_idle_resize (gpointer arg)
5141 return ((Editor*)arg)->idle_resize ();
5145 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5147 if (resize_idle_id < 0) {
5148 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5149 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5150 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5152 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5153 _pending_resize_amount = 0;
5156 /* make a note of the smallest resulting height, so that we can clamp the
5157 lower limit at TimeAxisView::hSmall */
5159 int32_t min_resulting = INT32_MAX;
5161 _pending_resize_amount += h;
5162 _pending_resize_view = view;
5164 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5166 if (selection->tracks.contains (_pending_resize_view)) {
5167 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5168 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5172 if (min_resulting < 0) {
5177 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5178 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5182 /** Handle pending resizing of tracks */
5184 Editor::idle_resize ()
5186 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5188 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5189 selection->tracks.contains (_pending_resize_view)) {
5191 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5192 if (*i != _pending_resize_view) {
5193 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5198 _pending_resize_amount = 0;
5199 _group_tabs->set_dirty ();
5200 resize_idle_id = -1;
5208 ENSURE_GUI_THREAD (*this, &Editor::located);
5211 playhead_cursor->set_position (_session->audible_frame ());
5212 if (_follow_playhead && !_pending_initial_locate) {
5213 reset_x_origin_to_follow_playhead ();
5217 _pending_locate_request = false;
5218 _pending_initial_locate = false;
5222 Editor::region_view_added (RegionView * rv)
5224 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5225 if (rv->region ()->id () == (*pr)) {
5226 selection->add (rv);
5227 selection->regions.pending.erase (pr);
5232 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5234 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5235 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5236 if (rv->region()->id () == (*rnote).first) {
5237 mrv->select_notes ((*rnote).second);
5238 selection->pending_midi_note_selection.erase(rnote);
5244 _summary->set_background_dirty ();
5248 Editor::region_view_removed ()
5250 _summary->set_background_dirty ();
5254 Editor::axis_view_from_stripable (boost::shared_ptr<Stripable> s) const
5256 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5257 if ((*j)->stripable() == s) {
5267 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5271 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5272 TimeAxisView* tv = axis_view_from_stripable (*i);
5282 Editor::suspend_route_redisplay ()
5285 _routes->suspend_redisplay();
5290 Editor::resume_route_redisplay ()
5293 _routes->redisplay(); // queue redisplay
5294 _routes->resume_redisplay();
5299 Editor::add_vcas (VCAList& vlist)
5303 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5304 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5307 add_stripables (sl);
5311 Editor::add_routes (RouteList& rlist)
5315 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5319 add_stripables (sl);
5323 Editor::add_stripables (StripableList& sl)
5325 list<TimeAxisView*> new_views;
5326 boost::shared_ptr<VCA> v;
5327 boost::shared_ptr<Route> r;
5328 TrackViewList new_selection;
5329 bool from_scratch = (track_views.size() == 0);
5331 sl.sort (StripablePresentationInfoSorter());
5333 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5335 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5337 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5339 new_views.push_back (vtv);
5341 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5343 if (r->is_auditioner() || r->is_monitor()) {
5347 RouteTimeAxisView* rtv;
5348 DataType dt = r->input()->default_type();
5350 if (dt == ARDOUR::DataType::AUDIO) {
5351 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5353 } else if (dt == ARDOUR::DataType::MIDI) {
5354 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5357 throw unknown_type();
5360 new_views.push_back (rtv);
5361 track_views.push_back (rtv);
5362 new_selection.push_back (rtv);
5364 rtv->effective_gain_display ();
5366 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5367 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5371 if (new_views.size() > 0) {
5372 _routes->time_axis_views_added (new_views);
5373 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5376 /* note: !new_selection.empty() means that we got some routes rather
5380 if (!from_scratch && !new_selection.empty()) {
5381 selection->tracks.clear();
5382 selection->add (new_selection);
5383 begin_selection_op_history();
5386 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5387 show_editor_mixer (true);
5390 editor_list_button.set_sensitive (true);
5394 Editor::timeaxisview_deleted (TimeAxisView *tv)
5396 if (tv == entered_track) {
5400 if (_session && _session->deletion_in_progress()) {
5401 /* the situation is under control */
5405 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5407 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5409 _routes->route_removed (tv);
5411 TimeAxisView::Children c = tv->get_child_list ();
5412 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5413 if (entered_track == i->get()) {
5418 /* remove it from the list of track views */
5420 TrackViewList::iterator i;
5422 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5423 i = track_views.erase (i);
5426 /* update whatever the current mixer strip is displaying, if revelant */
5428 boost::shared_ptr<Route> route;
5431 route = rtav->route ();
5434 if (current_mixer_strip && current_mixer_strip->route() == route) {
5436 TimeAxisView* next_tv;
5438 if (track_views.empty()) {
5440 } else if (i == track_views.end()) {
5441 next_tv = track_views.front();
5446 // skip VCAs (cannot be selected, n/a in editor-mixer)
5447 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5448 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5449 next_tv = track_views.front();
5451 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5452 /* just in case: no master, only a VCA remains */
5458 set_selected_mixer_strip (*next_tv);
5460 /* make the editor mixer strip go away setting the
5461 * button to inactive (which also unticks the menu option)
5464 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5470 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5472 if (apply_to_selection) {
5473 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5475 TrackSelection::iterator j = i;
5478 hide_track_in_display (*i, false);
5483 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5485 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5486 // this will hide the mixer strip
5487 set_selected_mixer_strip (*tv);
5490 _routes->hide_track_in_display (*tv);
5495 Editor::sync_track_view_list_and_routes ()
5497 track_views = TrackViewList (_routes->views ());
5499 _summary->set_background_dirty();
5500 _group_tabs->set_dirty ();
5502 return false; // do not call again (until needed)
5506 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5508 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5513 /** Find a RouteTimeAxisView by the ID of its route */
5515 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5517 RouteTimeAxisView* v;
5519 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5520 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5521 if(v->route()->id() == id) {
5531 Editor::fit_route_group (RouteGroup *g)
5533 TrackViewList ts = axis_views_from_routes (g->route_list ());
5538 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5540 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5543 _session->cancel_audition ();
5547 if (_session->is_auditioning()) {
5548 _session->cancel_audition ();
5549 if (r == last_audition_region) {
5554 _session->audition_region (r);
5555 last_audition_region = r;
5560 Editor::hide_a_region (boost::shared_ptr<Region> r)
5562 r->set_hidden (true);
5566 Editor::show_a_region (boost::shared_ptr<Region> r)
5568 r->set_hidden (false);
5572 Editor::audition_region_from_region_list ()
5574 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5578 Editor::hide_region_from_region_list ()
5580 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5584 Editor::show_region_in_region_list ()
5586 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5590 Editor::step_edit_status_change (bool yn)
5593 start_step_editing ();
5595 stop_step_editing ();
5600 Editor::start_step_editing ()
5602 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5606 Editor::stop_step_editing ()
5608 step_edit_connection.disconnect ();
5612 Editor::check_step_edit ()
5614 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5615 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5617 mtv->check_step_edit ();
5621 return true; // do it again, till we stop
5625 Editor::scroll_press (Direction dir)
5627 ++_scroll_callbacks;
5629 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5630 /* delay the first auto-repeat */
5636 scroll_backward (1);
5644 scroll_up_one_track ();
5648 scroll_down_one_track ();
5652 /* do hacky auto-repeat */
5653 if (!_scroll_connection.connected ()) {
5655 _scroll_connection = Glib::signal_timeout().connect (
5656 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5659 _scroll_callbacks = 0;
5666 Editor::scroll_release ()
5668 _scroll_connection.disconnect ();
5671 /** Queue a change for the Editor viewport x origin to follow the playhead */
5673 Editor::reset_x_origin_to_follow_playhead ()
5675 framepos_t const frame = playhead_cursor->current_frame ();
5677 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5679 if (_session->transport_speed() < 0) {
5681 if (frame > (current_page_samples() / 2)) {
5682 center_screen (frame-(current_page_samples()/2));
5684 center_screen (current_page_samples()/2);
5691 if (frame < leftmost_frame) {
5693 if (_session->transport_rolling()) {
5694 /* rolling; end up with the playhead at the right of the page */
5695 l = frame - current_page_samples ();
5697 /* not rolling: end up with the playhead 1/4 of the way along the page */
5698 l = frame - current_page_samples() / 4;
5702 if (_session->transport_rolling()) {
5703 /* rolling: end up with the playhead on the left of the page */
5706 /* not rolling: end up with the playhead 3/4 of the way along the page */
5707 l = frame - 3 * current_page_samples() / 4;
5715 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5721 Editor::super_rapid_screen_update ()
5723 if (!_session || !_session->engine().running()) {
5727 /* METERING / MIXER STRIPS */
5729 /* update track meters, if required */
5730 if (contents().is_mapped() && meters_running) {
5731 RouteTimeAxisView* rtv;
5732 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5733 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5734 rtv->fast_update ();
5739 /* and any current mixer strip */
5740 if (current_mixer_strip) {
5741 current_mixer_strip->fast_update ();
5744 /* PLAYHEAD AND VIEWPORT */
5746 framepos_t const frame = _session->audible_frame();
5748 /* There are a few reasons why we might not update the playhead / viewport stuff:
5750 * 1. we don't update things when there's a pending locate request, otherwise
5751 * when the editor requests a locate there is a chance that this method
5752 * will move the playhead before the locate request is processed, causing
5754 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5755 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5758 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5760 last_update_frame = frame;
5762 if (!_dragging_playhead) {
5763 playhead_cursor->set_position (frame);
5766 if (!_stationary_playhead) {
5768 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5769 /* We only do this if we aren't already
5770 handling a visual change (ie if
5771 pending_visual_change.being_handled is
5772 false) so that these requests don't stack
5773 up there are too many of them to handle in
5776 reset_x_origin_to_follow_playhead ();
5781 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5782 framepos_t const frame = playhead_cursor->current_frame ();
5783 double target = ((double)frame - (double)current_page_samples()/2.0);
5784 if (target <= 0.0) {
5787 // compare to EditorCursor::set_position()
5788 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5789 double const new_pos = sample_to_pixel_unrounded (target);
5790 if (rint (new_pos) != rint (old_pos)) {
5791 reset_x_origin (pixel_to_sample (floor (new_pos)));
5802 Editor::session_going_away ()
5804 _have_idled = false;
5806 _session_connections.drop_connections ();
5808 super_rapid_screen_update_connection.disconnect ();
5810 selection->clear ();
5811 cut_buffer->clear ();
5813 clicked_regionview = 0;
5814 clicked_axisview = 0;
5815 clicked_routeview = 0;
5816 entered_regionview = 0;
5818 last_update_frame = 0;
5821 playhead_cursor->hide ();
5823 /* rip everything out of the list displays */
5827 _route_groups->clear ();
5829 /* do this first so that deleting a track doesn't reset cms to null
5830 and thus cause a leak.
5833 if (current_mixer_strip) {
5834 if (current_mixer_strip->get_parent() != 0) {
5835 global_hpacker.remove (*current_mixer_strip);
5837 delete current_mixer_strip;
5838 current_mixer_strip = 0;
5841 /* delete all trackviews */
5843 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5846 track_views.clear ();
5848 nudge_clock->set_session (0);
5850 editor_list_button.set_active(false);
5851 editor_list_button.set_sensitive(false);
5853 /* clear tempo/meter rulers */
5854 remove_metric_marks ();
5856 clear_marker_display ();
5858 stop_step_editing ();
5862 /* get rid of any existing editor mixer strip */
5864 WindowTitle title(Glib::get_application_name());
5865 title += _("Editor");
5867 own_window()->set_title (title.get_string());
5870 SessionHandlePtr::session_going_away ();
5874 Editor::trigger_script (int i)
5876 LuaInstance::instance()-> call_action (i);
5880 Editor::set_script_action_name (int i, const std::string& n)
5882 string const a = string_compose (X_("script-action-%1"), i + 1);
5883 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5886 act->set_label (string_compose (_("Unset #%1"), i + 1));
5887 act->set_tooltip (_("no action bound"));
5888 act->set_sensitive (false);
5891 act->set_tooltip (n);
5892 act->set_sensitive (true);
5894 KeyEditor::UpdateBindings ();
5898 Editor::show_editor_list (bool yn)
5901 _editor_list_vbox.show ();
5903 _editor_list_vbox.hide ();
5908 Editor::change_region_layering_order (bool from_context_menu)
5910 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5912 if (!clicked_routeview) {
5913 if (layering_order_editor) {
5914 layering_order_editor->hide ();
5919 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5925 boost::shared_ptr<Playlist> pl = track->playlist();
5931 if (layering_order_editor == 0) {
5932 layering_order_editor = new RegionLayeringOrderEditor (*this);
5935 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5936 layering_order_editor->maybe_present ();
5940 Editor::update_region_layering_order_editor ()
5942 if (layering_order_editor && layering_order_editor->is_visible ()) {
5943 change_region_layering_order (true);
5948 Editor::setup_fade_images ()
5950 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5951 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5952 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5953 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5954 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5956 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5957 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5958 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5959 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5960 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5964 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5966 Editor::action_menu_item (std::string const & name)
5968 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5971 return *manage (a->create_menu_item ());
5975 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5977 EventBox* b = manage (new EventBox);
5978 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5979 Label* l = manage (new Label (name));
5983 _the_notebook.append_page (widget, *b);
5987 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5989 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5990 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5993 if (ev->type == GDK_2BUTTON_PRESS) {
5995 /* double-click on a notebook tab shrinks or expands the notebook */
5997 if (_notebook_shrunk) {
5998 if (pre_notebook_shrink_pane_width) {
5999 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6001 _notebook_shrunk = false;
6003 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6005 /* this expands the LHS of the edit pane to cover the notebook
6006 PAGE but leaves the tabs visible.
6008 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6009 _notebook_shrunk = true;
6017 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6019 using namespace Menu_Helpers;
6021 MenuList& items = _control_point_context_menu.items ();
6024 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6025 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6026 if (!can_remove_control_point (item)) {
6027 items.back().set_sensitive (false);
6030 _control_point_context_menu.popup (event->button.button, event->button.time);
6034 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6036 using namespace Menu_Helpers;
6038 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6043 /* We need to get the selection here and pass it to the operations, since
6044 popping up the menu will cause a region leave event which clears
6045 entered_regionview. */
6047 MidiRegionView& mrv = note->region_view();
6048 const RegionSelection rs = get_regions_from_selection_and_entered ();
6049 const uint32_t sel_size = mrv.selection_size ();
6051 MenuList& items = _note_context_menu.items();
6055 items.push_back(MenuElem(_("Delete"),
6056 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6059 items.push_back(MenuElem(_("Edit..."),
6060 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6061 if (sel_size != 1) {
6062 items.back().set_sensitive (false);
6065 items.push_back(MenuElem(_("Transpose..."),
6066 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6069 items.push_back(MenuElem(_("Legatize"),
6070 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6072 items.back().set_sensitive (false);
6075 items.push_back(MenuElem(_("Quantize..."),
6076 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6078 items.push_back(MenuElem(_("Remove Overlap"),
6079 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6081 items.back().set_sensitive (false);
6084 items.push_back(MenuElem(_("Transform..."),
6085 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6087 _note_context_menu.popup (event->button.button, event->button.time);
6091 Editor::zoom_vertical_modifier_released()
6093 _stepping_axis_view = 0;
6097 Editor::ui_parameter_changed (string parameter)
6099 if (parameter == "icon-set") {
6100 while (!_cursor_stack.empty()) {
6101 _cursor_stack.pop_back();
6103 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6104 _cursor_stack.push_back(_cursors->grabber);
6105 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6106 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6108 } else if (parameter == "draggable-playhead") {
6109 if (_verbose_cursor) {
6110 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6116 Editor::use_own_window (bool and_fill_it)
6118 bool new_window = !own_window();
6120 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6122 if (win && new_window) {
6123 win->set_name ("EditorWindow");
6125 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6127 // win->signal_realize().connect (*this, &Editor::on_realize);
6128 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6129 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6130 win->set_data ("ardour-bindings", bindings);
6135 DisplaySuspender ds;
6136 contents().show_all ();
6138 /* XXX: this is a bit unfortunate; it would probably
6139 be nicer if we could just call show () above rather
6140 than needing the show_all ()
6143 /* re-hide stuff if necessary */
6144 editor_list_button_toggled ();
6145 parameter_changed ("show-summary");
6146 parameter_changed ("show-group-tabs");
6147 parameter_changed ("show-zoom-tools");
6149 /* now reset all audio_time_axis heights, because widgets might need
6155 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6156 tv = (static_cast<TimeAxisView*>(*i));
6157 tv->reset_height ();
6160 if (current_mixer_strip) {
6161 current_mixer_strip->hide_things ();
6162 current_mixer_strip->parameter_changed ("mixer-element-visibility");