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 "audio_clock.h"
91 #include "audio_region_view.h"
92 #include "audio_streamview.h"
93 #include "audio_time_axis.h"
94 #include "automation_time_axis.h"
95 #include "bundle_manager.h"
96 #include "crossfade_edit.h"
100 #include "editor_cursors.h"
101 #include "editor_drag.h"
102 #include "editor_group_tabs.h"
103 #include "editor_locations.h"
104 #include "editor_regions.h"
105 #include "editor_route_groups.h"
106 #include "editor_routes.h"
107 #include "editor_snapshots.h"
108 #include "editor_summary.h"
109 #include "export_report.h"
110 #include "global_port_matrix.h"
111 #include "gui_object.h"
112 #include "gui_thread.h"
113 #include "keyboard.h"
114 #include "keyeditor.h"
115 #include "luainstance.h"
117 #include "midi_region_view.h"
118 #include "midi_time_axis.h"
119 #include "mixer_strip.h"
120 #include "mixer_ui.h"
121 #include "mouse_cursors.h"
122 #include "note_base.h"
123 #include "playlist_selector.h"
124 #include "public_editor.h"
125 #include "quantize_dialog.h"
126 #include "region_layering_order_editor.h"
127 #include "rgb_macros.h"
128 #include "rhythm_ferret.h"
129 #include "route_sorter.h"
130 #include "selection.h"
131 #include "simple_progress_dialog.h"
133 #include "tempo_lines.h"
134 #include "time_axis_view.h"
136 #include "tooltips.h"
137 #include "ui_config.h"
139 #include "vca_time_axis.h"
140 #include "verbose_cursor.h"
145 using namespace ARDOUR;
146 using namespace ARDOUR_UI_UTILS;
149 using namespace Glib;
150 using namespace Gtkmm2ext;
151 using namespace Editing;
153 using PBD::internationalize;
155 using Gtkmm2ext::Keyboard;
157 double Editor::timebar_height = 15.0;
159 static const gchar *_snap_type_strings[] = {
193 static const gchar *_snap_mode_strings[] = {
200 static const gchar *_edit_point_strings[] = {
207 static const gchar *_edit_mode_strings[] = {
215 static const gchar *_zoom_focus_strings[] = {
225 #ifdef USE_RUBBERBAND
226 static const gchar *_rb_opt_strings[] = {
229 N_("Balanced multitimbral mixture"),
230 N_("Unpitched percussion with stable notes"),
231 N_("Crisp monophonic instrumental"),
232 N_("Unpitched solo percussion"),
233 N_("Resample without preserving pitch"),
238 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
241 : PublicEditor (global_hpacker)
242 , editor_mixer_strip_width (Wide)
243 , constructed (false)
244 , _playlist_selector (0)
245 , no_save_visual (false)
247 , samples_per_pixel (2048)
248 , zoom_focus (ZoomFocusPlayhead)
249 , mouse_mode (MouseObject)
250 , pre_internal_snap_type (SnapToBeat)
251 , pre_internal_snap_mode (SnapOff)
252 , internal_snap_type (SnapToBeat)
253 , internal_snap_mode (SnapOff)
254 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
255 , _notebook_shrunk (false)
256 , location_marker_color (0)
257 , location_range_color (0)
258 , location_loop_color (0)
259 , location_punch_color (0)
260 , location_cd_marker_color (0)
262 , _show_marker_lines (false)
263 , clicked_axisview (0)
264 , clicked_routeview (0)
265 , clicked_regionview (0)
266 , clicked_selection (0)
267 , clicked_control_point (0)
268 , button_release_can_deselect (true)
269 , _mouse_changed_selection (false)
270 , region_edit_menu_split_item (0)
271 , region_edit_menu_split_multichannel_item (0)
272 , track_region_edit_playlist_menu (0)
273 , track_edit_playlist_submenu (0)
274 , track_selection_edit_playlist_submenu (0)
275 , _popup_region_menu_item (0)
277 , _track_canvas_viewport (0)
278 , within_track_canvas (false)
279 , _verbose_cursor (0)
283 , range_marker_group (0)
284 , transport_marker_group (0)
285 , cd_marker_group (0)
286 , _time_markers_group (0)
287 , hv_scroll_group (0)
289 , cursor_scroll_group (0)
290 , no_scroll_group (0)
291 , _trackview_group (0)
292 , _drag_motion_group (0)
293 , _canvas_drop_zone (0)
294 , no_ruler_shown_update (false)
295 , ruler_grabbed_widget (0)
297 , minsec_mark_interval (0)
298 , minsec_mark_modulo (0)
300 , timecode_mark_modulo (0)
301 , timecode_nmarks (0)
302 , _samples_ruler_interval (0)
305 , bbt_bar_helper_on (0)
306 , bbt_accent_modulo (0)
311 , visible_timebars (0)
312 , editor_ruler_menu (0)
316 , range_marker_bar (0)
317 , transport_marker_bar (0)
319 , minsec_label (_("Mins:Secs"))
320 , bbt_label (_("Bars:Beats"))
321 , timecode_label (_("Timecode"))
322 , samples_label (_("Samples"))
323 , tempo_label (_("Tempo"))
324 , meter_label (_("Meter"))
325 , mark_label (_("Location Markers"))
326 , range_mark_label (_("Range Markers"))
327 , transport_mark_label (_("Loop/Punch Ranges"))
328 , cd_mark_label (_("CD Markers"))
329 , videotl_label (_("Video Timeline"))
331 , playhead_cursor (0)
332 , edit_packer (4, 4, true)
333 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
334 , horizontal_adjustment (0.0, 0.0, 1e16)
335 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
336 , controls_layout (unused_adjustment, vertical_adjustment)
337 , _scroll_callbacks (0)
338 , _visible_canvas_width (0)
339 , _visible_canvas_height (0)
340 , _full_canvas_height (0)
341 , edit_controls_left_menu (0)
342 , edit_controls_right_menu (0)
343 , last_update_frame (0)
344 , cut_buffer_start (0)
345 , cut_buffer_length (0)
346 , button_bindings (0)
350 , current_interthread_info (0)
351 , analysis_window (0)
352 , select_new_marker (false)
354 , scrubbing_direction (0)
355 , scrub_reversals (0)
356 , scrub_reverse_distance (0)
357 , have_pending_keyboard_selection (false)
358 , pending_keyboard_selection_start (0)
359 , _snap_type (SnapToBeat)
360 , _snap_mode (SnapOff)
361 , snap_threshold (5.0)
362 , ignore_gui_changes (false)
363 , _drags (new DragManager (this))
365 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
366 , _dragging_playhead (false)
367 , _dragging_edit_point (false)
368 , _show_measures (true)
369 , _follow_playhead (true)
370 , _stationary_playhead (false)
373 , global_rect_group (0)
374 , time_line_group (0)
375 , tempo_marker_menu (0)
376 , meter_marker_menu (0)
378 , range_marker_menu (0)
379 , transport_marker_menu (0)
380 , new_transport_marker_menu (0)
382 , marker_menu_item (0)
383 , bbt_beat_subdivision (4)
384 , _visible_track_count (-1)
385 , toolbar_selection_clock_table (2,3)
386 , automation_mode_button (_("mode"))
387 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
388 , selection (new Selection (this))
389 , cut_buffer (new Selection (this))
390 , _selection_memento (new SelectionMemento())
391 , _all_region_actions_sensitized (false)
392 , _ignore_region_action (false)
393 , _last_region_menu_was_main (false)
394 , _ignore_follow_edits (false)
395 , cd_marker_bar_drag_rect (0)
396 , range_bar_drag_rect (0)
397 , transport_bar_drag_rect (0)
398 , transport_bar_range_rect (0)
399 , transport_bar_preroll_rect (0)
400 , transport_bar_postroll_rect (0)
401 , transport_loop_range_rect (0)
402 , transport_punch_range_rect (0)
403 , transport_punchin_line (0)
404 , transport_punchout_line (0)
405 , transport_preroll_rect (0)
406 , transport_postroll_rect (0)
408 , rubberband_rect (0)
414 , autoscroll_horizontal_allowed (false)
415 , autoscroll_vertical_allowed (false)
417 , autoscroll_widget (0)
418 , show_gain_after_trim (false)
419 , selection_op_cmd_depth (0)
420 , selection_op_history_it (0)
421 , no_save_instant (false)
423 , current_mixer_strip (0)
424 , show_editor_mixer_when_tracks_arrive (false)
425 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
426 , current_stepping_trackview (0)
427 , last_track_height_step_timestamp (0)
429 , entered_regionview (0)
430 , clear_entered_track (false)
431 , _edit_point (EditAtMouse)
432 , meters_running (false)
434 , _have_idled (false)
435 , resize_idle_id (-1)
436 , _pending_resize_amount (0)
437 , _pending_resize_view (0)
438 , _pending_locate_request (false)
439 , _pending_initial_locate (false)
443 , layering_order_editor (0)
444 , _last_cut_copy_source_track (0)
445 , _region_selection_change_updates_region_list (true)
447 , _following_mixer_selection (false)
448 , _control_point_toggled_on_press (false)
449 , _stepping_axis_view (0)
450 , quantize_dialog (0)
451 , _main_menu_disabler (0)
452 , myactions (X_("editor"))
454 /* we are a singleton */
456 PublicEditor::_instance = this;
460 last_event_time.tv_sec = 0;
461 last_event_time.tv_usec = 0;
463 selection_op_history.clear();
466 snap_type_strings = I18N (_snap_type_strings);
467 snap_mode_strings = I18N (_snap_mode_strings);
468 zoom_focus_strings = I18N (_zoom_focus_strings);
469 edit_mode_strings = I18N (_edit_mode_strings);
470 edit_point_strings = I18N (_edit_point_strings);
471 #ifdef USE_RUBBERBAND
472 rb_opt_strings = I18N (_rb_opt_strings);
476 build_edit_mode_menu();
477 build_zoom_focus_menu();
478 build_track_count_menu();
479 build_snap_mode_menu();
480 build_snap_type_menu();
481 build_edit_point_menu();
483 location_marker_color = UIConfiguration::instance().color ("location marker");
484 location_range_color = UIConfiguration::instance().color ("location range");
485 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
486 location_loop_color = UIConfiguration::instance().color ("location loop");
487 location_punch_color = UIConfiguration::instance().color ("location punch");
489 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
491 TimeAxisView::setup_sizes ();
492 ArdourMarker::setup_sizes (timebar_height);
493 TempoCurve::setup_sizes (timebar_height);
495 bbt_label.set_name ("EditorRulerLabel");
496 bbt_label.set_size_request (-1, (int)timebar_height);
497 bbt_label.set_alignment (1.0, 0.5);
498 bbt_label.set_padding (5,0);
500 bbt_label.set_no_show_all();
501 minsec_label.set_name ("EditorRulerLabel");
502 minsec_label.set_size_request (-1, (int)timebar_height);
503 minsec_label.set_alignment (1.0, 0.5);
504 minsec_label.set_padding (5,0);
505 minsec_label.hide ();
506 minsec_label.set_no_show_all();
507 timecode_label.set_name ("EditorRulerLabel");
508 timecode_label.set_size_request (-1, (int)timebar_height);
509 timecode_label.set_alignment (1.0, 0.5);
510 timecode_label.set_padding (5,0);
511 timecode_label.hide ();
512 timecode_label.set_no_show_all();
513 samples_label.set_name ("EditorRulerLabel");
514 samples_label.set_size_request (-1, (int)timebar_height);
515 samples_label.set_alignment (1.0, 0.5);
516 samples_label.set_padding (5,0);
517 samples_label.hide ();
518 samples_label.set_no_show_all();
520 tempo_label.set_name ("EditorRulerLabel");
521 tempo_label.set_size_request (-1, (int)timebar_height);
522 tempo_label.set_alignment (1.0, 0.5);
523 tempo_label.set_padding (5,0);
525 tempo_label.set_no_show_all();
527 meter_label.set_name ("EditorRulerLabel");
528 meter_label.set_size_request (-1, (int)timebar_height);
529 meter_label.set_alignment (1.0, 0.5);
530 meter_label.set_padding (5,0);
532 meter_label.set_no_show_all();
534 if (Profile->get_trx()) {
535 mark_label.set_text (_("Markers"));
537 mark_label.set_name ("EditorRulerLabel");
538 mark_label.set_size_request (-1, (int)timebar_height);
539 mark_label.set_alignment (1.0, 0.5);
540 mark_label.set_padding (5,0);
542 mark_label.set_no_show_all();
544 cd_mark_label.set_name ("EditorRulerLabel");
545 cd_mark_label.set_size_request (-1, (int)timebar_height);
546 cd_mark_label.set_alignment (1.0, 0.5);
547 cd_mark_label.set_padding (5,0);
548 cd_mark_label.hide();
549 cd_mark_label.set_no_show_all();
551 videotl_bar_height = 4;
552 videotl_label.set_name ("EditorRulerLabel");
553 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
554 videotl_label.set_alignment (1.0, 0.5);
555 videotl_label.set_padding (5,0);
556 videotl_label.hide();
557 videotl_label.set_no_show_all();
559 range_mark_label.set_name ("EditorRulerLabel");
560 range_mark_label.set_size_request (-1, (int)timebar_height);
561 range_mark_label.set_alignment (1.0, 0.5);
562 range_mark_label.set_padding (5,0);
563 range_mark_label.hide();
564 range_mark_label.set_no_show_all();
566 transport_mark_label.set_name ("EditorRulerLabel");
567 transport_mark_label.set_size_request (-1, (int)timebar_height);
568 transport_mark_label.set_alignment (1.0, 0.5);
569 transport_mark_label.set_padding (5,0);
570 transport_mark_label.hide();
571 transport_mark_label.set_no_show_all();
573 initialize_canvas ();
575 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
577 _summary = new EditorSummary (this);
579 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
580 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_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);
647 /* these are static location signals */
649 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
650 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
651 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
653 add_notebook_page (_("Regions"), _regions->widget ());
654 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
655 add_notebook_page (_("Snapshots"), _snapshots->widget ());
656 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
657 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
659 _the_notebook.set_show_tabs (true);
660 _the_notebook.set_scrollable (true);
661 _the_notebook.popup_disable ();
662 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
663 _the_notebook.show_all ();
665 _notebook_shrunk = false;
668 /* Pick up some settings we need to cache, early */
670 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
673 if (settings && (prop = settings->property ("notebook-shrunk"))) {
674 _notebook_shrunk = string_is_affirmative (prop->value ());
677 editor_summary_pane.set_check_divider_position (true);
678 editor_summary_pane.add (edit_packer);
680 Button* summary_arrows_left_left = manage (new Button);
681 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
682 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
683 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
685 Button* summary_arrows_left_right = manage (new Button);
686 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
687 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
688 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
690 VBox* summary_arrows_left = manage (new VBox);
691 summary_arrows_left->pack_start (*summary_arrows_left_left);
692 summary_arrows_left->pack_start (*summary_arrows_left_right);
694 Button* summary_arrows_right_up = manage (new Button);
695 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
696 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
697 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
699 Button* summary_arrows_right_down = manage (new Button);
700 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
701 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
702 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
704 VBox* summary_arrows_right = manage (new VBox);
705 summary_arrows_right->pack_start (*summary_arrows_right_up);
706 summary_arrows_right->pack_start (*summary_arrows_right_down);
708 Frame* summary_frame = manage (new Frame);
709 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
711 summary_frame->add (*_summary);
712 summary_frame->show ();
714 _summary_hbox.pack_start (*summary_arrows_left, false, false);
715 _summary_hbox.pack_start (*summary_frame, true, true);
716 _summary_hbox.pack_start (*summary_arrows_right, false, false);
718 if (!ARDOUR::Profile->get_trx()) {
719 editor_summary_pane.add (_summary_hbox);
722 edit_pane.set_check_divider_position (true);
723 edit_pane.add (editor_summary_pane);
724 if (!ARDOUR::Profile->get_trx()) {
725 edit_pane.add (_the_notebook);
728 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
729 edit_pane.set_child_minsize (_the_notebook, 30); /* rough guess at width of notebook tabs */
730 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
737 if (!settings || ((prop = settings->property ("edit-horizontal-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
738 /* initial allocation is 90% to canvas, 10% to notebook */
739 edit_pane.set_divider (0, 0.90);
741 edit_pane.set_divider (0, fract);
744 if (!settings || ((prop = settings->property ("edit-vertical-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
745 /* initial allocation is 90% to canvas, 10% to summary */
746 editor_summary_pane.set_divider (0, 0.90);
749 editor_summary_pane.set_divider (0, fract);
753 top_hbox.pack_start (toolbar_frame);
755 HBox *hbox = manage (new HBox);
756 hbox->pack_start (edit_pane, true, true);
758 global_vpacker.pack_start (top_hbox, false, false);
759 global_vpacker.pack_start (*hbox, true, true);
760 global_hpacker.pack_start (global_vpacker, true, true);
762 /* need to show the "contents" widget so that notebook will show if tab is switched to
765 global_hpacker.show ();
767 /* register actions now so that set_state() can find them and set toggles/checks etc */
774 _playlist_selector = new PlaylistSelector();
775 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
777 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
781 nudge_forward_button.set_name ("nudge button");
782 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
784 nudge_backward_button.set_name ("nudge button");
785 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
787 fade_context_menu.set_name ("ArdourContextMenu");
789 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
791 /* allow external control surfaces/protocols to do various things */
793 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
794 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
795 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
796 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
797 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
798 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
799 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
800 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
801 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
802 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
803 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
804 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
805 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
806 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
808 ControlProtocol::AddStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
809 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
810 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
812 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
816 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
818 /* problematic: has to return a value and thus cannot be x-thread */
820 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
822 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
823 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
825 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
827 _ignore_region_action = false;
828 _last_region_menu_was_main = false;
829 _popup_region_menu_item = 0;
831 _ignore_follow_edits = false;
833 _show_marker_lines = false;
835 /* Button bindings */
837 button_bindings = new Bindings ("editor-mouse");
839 XMLNode* node = button_settings();
841 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
842 button_bindings->load_operation (**i);
848 /* grab current parameter state */
849 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
850 UIConfiguration::instance().map_parameters (pc);
852 setup_fade_images ();
854 LuaInstance::instance(); // instantiate
855 LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &Editor::set_script_action_name));
862 delete button_bindings;
864 delete _route_groups;
865 delete _track_canvas_viewport;
868 delete quantize_dialog;
874 delete _playlist_selector;
876 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
882 Editor::button_settings () const
884 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
885 XMLNode* node = find_named_node (*settings, X_("Buttons"));
888 node = new XMLNode (X_("Buttons"));
895 Editor::get_smart_mode () const
897 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
901 Editor::catch_vanishing_regionview (RegionView *rv)
903 /* note: the selection will take care of the vanishing
904 audioregionview by itself.
907 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
911 if (clicked_regionview == rv) {
912 clicked_regionview = 0;
915 if (entered_regionview == rv) {
916 set_entered_regionview (0);
919 if (!_all_region_actions_sensitized) {
920 sensitize_all_region_actions (true);
925 Editor::set_entered_regionview (RegionView* rv)
927 if (rv == entered_regionview) {
931 if (entered_regionview) {
932 entered_regionview->exited ();
935 entered_regionview = rv;
937 if (entered_regionview != 0) {
938 entered_regionview->entered ();
941 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
942 /* This RegionView entry might have changed what region actions
943 are allowed, so sensitize them all in case a key is pressed.
945 sensitize_all_region_actions (true);
950 Editor::set_entered_track (TimeAxisView* tav)
953 entered_track->exited ();
959 entered_track->entered ();
964 Editor::instant_save ()
966 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
971 _session->add_instant_xml(get_state());
973 Config->add_instant_xml(get_state());
978 Editor::control_vertical_zoom_in_all ()
980 tav_zoom_smooth (false, true);
984 Editor::control_vertical_zoom_out_all ()
986 tav_zoom_smooth (true, true);
990 Editor::control_vertical_zoom_in_selected ()
992 tav_zoom_smooth (false, false);
996 Editor::control_vertical_zoom_out_selected ()
998 tav_zoom_smooth (true, false);
1002 Editor::control_view (uint32_t view)
1004 goto_visual_state (view);
1008 Editor::control_unselect ()
1010 selection->clear_tracks ();
1014 Editor::control_select (PresentationInfo::order_t order, Selection::Operation op)
1016 /* handles the (static) signal from the ControlProtocol class that
1017 * requests setting the selected track to a given RID
1024 boost::shared_ptr<Stripable> s = _session->get_remote_nth_stripable (order, PresentationInfo::AllStripables);
1026 /* selected object may not be a Route */
1028 boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route> (s);
1034 TimeAxisView* tav = axis_view_from_route (r);
1038 case Selection::Add:
1039 selection->add (tav);
1041 case Selection::Toggle:
1042 selection->toggle (tav);
1044 case Selection::Extend:
1046 case Selection::Set:
1047 selection->set (tav);
1051 selection->clear_tracks ();
1056 Editor::control_step_tracks_up ()
1058 scroll_tracks_up_line ();
1062 Editor::control_step_tracks_down ()
1064 scroll_tracks_down_line ();
1068 Editor::control_scroll (float fraction)
1070 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1076 double step = fraction * current_page_samples();
1079 _control_scroll_target is an optional<T>
1081 it acts like a pointer to an framepos_t, with
1082 a operator conversion to boolean to check
1083 that it has a value could possibly use
1084 playhead_cursor->current_frame to store the
1085 value and a boolean in the class to know
1086 when it's out of date
1089 if (!_control_scroll_target) {
1090 _control_scroll_target = _session->transport_frame();
1091 _dragging_playhead = true;
1094 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1095 *_control_scroll_target = 0;
1096 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1097 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1099 *_control_scroll_target += (framepos_t) trunc (step);
1102 /* move visuals, we'll catch up with it later */
1104 playhead_cursor->set_position (*_control_scroll_target);
1105 UpdateAllTransportClocks (*_control_scroll_target);
1107 if (*_control_scroll_target > (current_page_samples() / 2)) {
1108 /* try to center PH in window */
1109 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1115 Now we do a timeout to actually bring the session to the right place
1116 according to the playhead. This is to avoid reading disk buffers on every
1117 call to control_scroll, which is driven by ScrollTimeline and therefore
1118 probably by a control surface wheel which can generate lots of events.
1120 /* cancel the existing timeout */
1122 control_scroll_connection.disconnect ();
1124 /* add the next timeout */
1126 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1130 Editor::deferred_control_scroll (framepos_t /*target*/)
1132 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1133 // reset for next stream
1134 _control_scroll_target = boost::none;
1135 _dragging_playhead = false;
1140 Editor::access_action (std::string action_group, std::string action_item)
1146 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1149 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1157 Editor::on_realize ()
1161 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1162 start_lock_event_timing ();
1167 Editor::start_lock_event_timing ()
1169 /* check if we should lock the GUI every 30 seconds */
1171 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1175 Editor::generic_event_handler (GdkEvent* ev)
1178 case GDK_BUTTON_PRESS:
1179 case GDK_BUTTON_RELEASE:
1180 case GDK_MOTION_NOTIFY:
1182 case GDK_KEY_RELEASE:
1183 if (contents().is_mapped()) {
1184 gettimeofday (&last_event_time, 0);
1188 case GDK_LEAVE_NOTIFY:
1189 switch (ev->crossing.detail) {
1190 case GDK_NOTIFY_UNKNOWN:
1191 case GDK_NOTIFY_INFERIOR:
1192 case GDK_NOTIFY_ANCESTOR:
1194 case GDK_NOTIFY_VIRTUAL:
1195 case GDK_NOTIFY_NONLINEAR:
1196 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1197 /* leaving window, so reset focus, thus ending any and
1198 all text entry operations.
1200 reset_focus (&contents());
1213 Editor::lock_timeout_callback ()
1215 struct timeval now, delta;
1217 gettimeofday (&now, 0);
1219 timersub (&now, &last_event_time, &delta);
1221 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1223 /* don't call again. Returning false will effectively
1224 disconnect us from the timer callback.
1226 unlock() will call start_lock_event_timing() to get things
1236 Editor::map_position_change (framepos_t frame)
1238 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1240 if (_session == 0) {
1244 if (_follow_playhead) {
1245 center_screen (frame);
1248 playhead_cursor->set_position (frame);
1252 Editor::center_screen (framepos_t frame)
1254 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1256 /* if we're off the page, then scroll.
1259 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1260 center_screen_internal (frame, page);
1265 Editor::center_screen_internal (framepos_t frame, float page)
1270 frame -= (framepos_t) page;
1275 reset_x_origin (frame);
1280 Editor::update_title ()
1282 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1284 if (!own_window()) {
1289 bool dirty = _session->dirty();
1291 string session_name;
1293 if (_session->snap_name() != _session->name()) {
1294 session_name = _session->snap_name();
1296 session_name = _session->name();
1300 session_name = "*" + session_name;
1303 WindowTitle title(session_name);
1304 title += S_("Window|Editor");
1305 title += Glib::get_application_name();
1306 own_window()->set_title (title.get_string());
1308 /* ::session_going_away() will have taken care of it */
1313 Editor::set_session (Session *t)
1315 SessionHandlePtr::set_session (t);
1321 _playlist_selector->set_session (_session);
1322 nudge_clock->set_session (_session);
1323 _summary->set_session (_session);
1324 _group_tabs->set_session (_session);
1325 _route_groups->set_session (_session);
1326 _regions->set_session (_session);
1327 _snapshots->set_session (_session);
1328 _routes->set_session (_session);
1329 _locations->set_session (_session);
1331 if (rhythm_ferret) {
1332 rhythm_ferret->set_session (_session);
1335 if (analysis_window) {
1336 analysis_window->set_session (_session);
1340 sfbrowser->set_session (_session);
1343 compute_fixed_ruler_scale ();
1345 /* Make sure we have auto loop and auto punch ranges */
1347 Location* loc = _session->locations()->auto_loop_location();
1349 loc->set_name (_("Loop"));
1352 loc = _session->locations()->auto_punch_location();
1355 loc->set_name (_("Punch"));
1358 refresh_location_display ();
1360 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1361 the selected Marker; this needs the LocationMarker list to be available.
1363 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1364 set_state (*node, Stateful::loading_state_version);
1366 /* catch up with the playhead */
1368 _session->request_locate (playhead_cursor->current_frame ());
1369 _pending_initial_locate = true;
1373 /* These signals can all be emitted by a non-GUI thread. Therefore the
1374 handlers for them must not attempt to directly interact with the GUI,
1375 but use PBD::Signal<T>::connect() which accepts an event loop
1376 ("context") where the handler will be asked to run.
1379 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1380 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1381 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1382 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1383 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1384 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1385 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1386 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::marker_position_changed, this), gui_context());
1387 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1388 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1389 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1390 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1391 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1392 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1393 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1395 playhead_cursor->show ();
1397 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1398 Config->map_parameters (pc);
1399 _session->config.map_parameters (pc);
1401 restore_ruler_visibility ();
1402 //tempo_map_changed (PropertyChange (0));
1403 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1405 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1406 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1409 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1410 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1413 switch (_snap_type) {
1414 case SnapToRegionStart:
1415 case SnapToRegionEnd:
1416 case SnapToRegionSync:
1417 case SnapToRegionBoundary:
1418 build_region_boundary_cache ();
1425 /* catch up on selection of stripables (other selection state is lost
1426 * when a session is closed
1431 _session->get_stripables (sl);
1432 for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
1433 if ((*s)->presentation_info().selected()) {
1434 RouteTimeAxisView* rtav = get_route_view_by_route_id ((*s)->id());
1436 tl.push_back (rtav);
1441 selection->set (tl);
1444 /* register for undo history */
1445 _session->register_with_memento_command_factory(id(), this);
1446 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1448 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1450 LuaInstance::instance()->set_session(_session);
1452 start_updating_meters ();
1456 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1458 if (a->get_name() == "RegionMenu") {
1459 /* When the main menu's region menu is opened, we setup the actions so that they look right
1460 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1461 so we resensitize all region actions when the entered regionview or the region selection
1462 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1463 happens after the region context menu is opened. So we set a flag here, too.
1467 sensitize_the_right_region_actions ();
1468 _last_region_menu_was_main = true;
1473 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1475 using namespace Menu_Helpers;
1477 void (Editor::*emf)(FadeShape);
1478 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1481 images = &_xfade_in_images;
1482 emf = &Editor::set_fade_in_shape;
1484 images = &_xfade_out_images;
1485 emf = &Editor::set_fade_out_shape;
1490 _("Linear (for highly correlated material)"),
1491 *(*images)[FadeLinear],
1492 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1496 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1500 _("Constant power"),
1501 *(*images)[FadeConstantPower],
1502 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1505 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1510 *(*images)[FadeSymmetric],
1511 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1515 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1520 *(*images)[FadeSlow],
1521 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1524 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1529 *(*images)[FadeFast],
1530 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1533 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1536 /** Pop up a context menu for when the user clicks on a start crossfade */
1538 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1540 using namespace Menu_Helpers;
1541 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1546 MenuList& items (xfade_in_context_menu.items());
1549 if (arv->audio_region()->fade_in_active()) {
1550 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1552 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1555 items.push_back (SeparatorElem());
1556 fill_xfade_menu (items, true);
1558 xfade_in_context_menu.popup (button, time);
1561 /** Pop up a context menu for when the user clicks on an end crossfade */
1563 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1565 using namespace Menu_Helpers;
1566 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1571 MenuList& items (xfade_out_context_menu.items());
1574 if (arv->audio_region()->fade_out_active()) {
1575 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1577 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1580 items.push_back (SeparatorElem());
1581 fill_xfade_menu (items, false);
1583 xfade_out_context_menu.popup (button, time);
1587 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1589 using namespace Menu_Helpers;
1590 Menu* (Editor::*build_menu_function)();
1593 switch (item_type) {
1595 case RegionViewName:
1596 case RegionViewNameHighlight:
1597 case LeftFrameHandle:
1598 case RightFrameHandle:
1599 if (with_selection) {
1600 build_menu_function = &Editor::build_track_selection_context_menu;
1602 build_menu_function = &Editor::build_track_region_context_menu;
1607 if (with_selection) {
1608 build_menu_function = &Editor::build_track_selection_context_menu;
1610 build_menu_function = &Editor::build_track_context_menu;
1615 if (clicked_routeview->track()) {
1616 build_menu_function = &Editor::build_track_context_menu;
1618 build_menu_function = &Editor::build_track_bus_context_menu;
1623 /* probably shouldn't happen but if it does, we don't care */
1627 menu = (this->*build_menu_function)();
1628 menu->set_name ("ArdourContextMenu");
1630 /* now handle specific situations */
1632 switch (item_type) {
1634 case RegionViewName:
1635 case RegionViewNameHighlight:
1636 case LeftFrameHandle:
1637 case RightFrameHandle:
1638 if (!with_selection) {
1639 if (region_edit_menu_split_item) {
1640 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1641 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1643 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1646 if (region_edit_menu_split_multichannel_item) {
1647 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1648 region_edit_menu_split_multichannel_item->set_sensitive (true);
1650 region_edit_menu_split_multichannel_item->set_sensitive (false);
1663 /* probably shouldn't happen but if it does, we don't care */
1667 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1669 /* Bounce to disk */
1671 using namespace Menu_Helpers;
1672 MenuList& edit_items = menu->items();
1674 edit_items.push_back (SeparatorElem());
1676 switch (clicked_routeview->audio_track()->freeze_state()) {
1677 case AudioTrack::NoFreeze:
1678 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1681 case AudioTrack::Frozen:
1682 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1685 case AudioTrack::UnFrozen:
1686 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1692 if (item_type == StreamItem && clicked_routeview) {
1693 clicked_routeview->build_underlay_menu(menu);
1696 /* When the region menu is opened, we setup the actions so that they look right
1699 sensitize_the_right_region_actions ();
1700 _last_region_menu_was_main = false;
1702 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1703 menu->popup (button, time);
1707 Editor::build_track_context_menu ()
1709 using namespace Menu_Helpers;
1711 MenuList& edit_items = track_context_menu.items();
1714 add_dstream_context_items (edit_items);
1715 return &track_context_menu;
1719 Editor::build_track_bus_context_menu ()
1721 using namespace Menu_Helpers;
1723 MenuList& edit_items = track_context_menu.items();
1726 add_bus_context_items (edit_items);
1727 return &track_context_menu;
1731 Editor::build_track_region_context_menu ()
1733 using namespace Menu_Helpers;
1734 MenuList& edit_items = track_region_context_menu.items();
1737 /* we've just cleared the track region context menu, so the menu that these
1738 two items were on will have disappeared; stop them dangling.
1740 region_edit_menu_split_item = 0;
1741 region_edit_menu_split_multichannel_item = 0;
1743 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1746 boost::shared_ptr<Track> tr;
1747 boost::shared_ptr<Playlist> pl;
1749 if ((tr = rtv->track())) {
1750 add_region_context_items (edit_items, tr);
1754 add_dstream_context_items (edit_items);
1756 return &track_region_context_menu;
1760 Editor::loudness_analyze_region_selection ()
1765 Selection& s (PublicEditor::instance ().get_selection ());
1766 RegionSelection ars = s.regions;
1767 ARDOUR::AnalysisGraph ag (_session);
1768 framecnt_t total_work = 0;
1770 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1771 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1775 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1778 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1779 total_work += arv->region ()->length ();
1782 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1784 ag.set_total_frames (total_work);
1785 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1788 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1789 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1793 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1797 ag.analyze_region (ar);
1800 if (!ag.canceled ()) {
1801 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1807 Editor::loudness_analyze_range_selection ()
1812 Selection& s (PublicEditor::instance ().get_selection ());
1813 TimeSelection ts = s.time;
1814 ARDOUR::AnalysisGraph ag (_session);
1815 framecnt_t total_work = 0;
1817 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1818 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1822 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1826 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1827 total_work += j->length ();
1831 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1833 ag.set_total_frames (total_work);
1834 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1837 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1838 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1842 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1846 ag.analyze_range (rui->route (), pl, ts);
1849 if (!ag.canceled ()) {
1850 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1856 Editor::spectral_analyze_region_selection ()
1858 if (analysis_window == 0) {
1859 analysis_window = new AnalysisWindow();
1862 analysis_window->set_session(_session);
1864 analysis_window->show_all();
1867 analysis_window->set_regionmode();
1868 analysis_window->analyze();
1870 analysis_window->present();
1874 Editor::spectral_analyze_range_selection()
1876 if (analysis_window == 0) {
1877 analysis_window = new AnalysisWindow();
1880 analysis_window->set_session(_session);
1882 analysis_window->show_all();
1885 analysis_window->set_rangemode();
1886 analysis_window->analyze();
1888 analysis_window->present();
1892 Editor::build_track_selection_context_menu ()
1894 using namespace Menu_Helpers;
1895 MenuList& edit_items = track_selection_context_menu.items();
1896 edit_items.clear ();
1898 add_selection_context_items (edit_items);
1899 // edit_items.push_back (SeparatorElem());
1900 // add_dstream_context_items (edit_items);
1902 return &track_selection_context_menu;
1906 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1908 using namespace Menu_Helpers;
1910 /* OK, stick the region submenu at the top of the list, and then add
1914 RegionSelection rs = get_regions_from_selection_and_entered ();
1916 string::size_type pos = 0;
1917 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1919 /* we have to hack up the region name because "_" has a special
1920 meaning for menu titles.
1923 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1924 menu_item_name.replace (pos, 1, "__");
1928 if (_popup_region_menu_item == 0) {
1929 _popup_region_menu_item = new MenuItem (menu_item_name);
1930 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1931 _popup_region_menu_item->show ();
1933 _popup_region_menu_item->set_label (menu_item_name);
1936 /* No latering allowed in later is higher layering model */
1937 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1938 if (act && Config->get_layer_model() == LaterHigher) {
1939 act->set_sensitive (false);
1941 act->set_sensitive (true);
1944 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1946 edit_items.push_back (*_popup_region_menu_item);
1947 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1948 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1950 edit_items.push_back (SeparatorElem());
1953 /** Add context menu items relevant to selection ranges.
1954 * @param edit_items List to add the items to.
1957 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1959 using namespace Menu_Helpers;
1961 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1962 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1964 edit_items.push_back (SeparatorElem());
1965 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1967 edit_items.push_back (SeparatorElem());
1968 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1969 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1971 edit_items.push_back (SeparatorElem());
1973 edit_items.push_back (
1975 _("Move Range Start to Previous Region Boundary"),
1976 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1980 edit_items.push_back (
1982 _("Move Range Start to Next Region Boundary"),
1983 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1987 edit_items.push_back (
1989 _("Move Range End to Previous Region Boundary"),
1990 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1994 edit_items.push_back (
1996 _("Move Range End to Next Region Boundary"),
1997 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
2001 edit_items.push_back (SeparatorElem());
2002 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
2003 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
2005 edit_items.push_back (SeparatorElem());
2006 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
2008 edit_items.push_back (SeparatorElem());
2009 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
2010 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
2011 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
2013 edit_items.push_back (SeparatorElem());
2014 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
2016 edit_items.push_back (SeparatorElem());
2017 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
2018 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
2020 edit_items.push_back (SeparatorElem());
2021 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
2022 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
2023 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
2024 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
2025 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
2026 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
2027 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2033 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2035 using namespace Menu_Helpers;
2039 Menu *play_menu = manage (new Menu);
2040 MenuList& play_items = play_menu->items();
2041 play_menu->set_name ("ArdourContextMenu");
2043 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2044 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2045 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2046 play_items.push_back (SeparatorElem());
2047 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2049 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2053 Menu *select_menu = manage (new Menu);
2054 MenuList& select_items = select_menu->items();
2055 select_menu->set_name ("ArdourContextMenu");
2057 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2058 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2059 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2060 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2061 select_items.push_back (SeparatorElem());
2062 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2063 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2064 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2065 select_items.push_back (SeparatorElem());
2066 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2067 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2068 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2069 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2070 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2071 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2072 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2074 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2078 Menu *cutnpaste_menu = manage (new Menu);
2079 MenuList& cutnpaste_items = cutnpaste_menu->items();
2080 cutnpaste_menu->set_name ("ArdourContextMenu");
2082 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2083 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2084 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2086 cutnpaste_items.push_back (SeparatorElem());
2088 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2089 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2091 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2093 /* Adding new material */
2095 edit_items.push_back (SeparatorElem());
2096 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2097 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2101 Menu *nudge_menu = manage (new Menu());
2102 MenuList& nudge_items = nudge_menu->items();
2103 nudge_menu->set_name ("ArdourContextMenu");
2105 edit_items.push_back (SeparatorElem());
2106 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2107 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2108 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2109 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2111 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2115 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2117 using namespace Menu_Helpers;
2121 Menu *play_menu = manage (new Menu);
2122 MenuList& play_items = play_menu->items();
2123 play_menu->set_name ("ArdourContextMenu");
2125 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2126 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2127 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2131 Menu *select_menu = manage (new Menu);
2132 MenuList& select_items = select_menu->items();
2133 select_menu->set_name ("ArdourContextMenu");
2135 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2136 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2137 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2138 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2139 select_items.push_back (SeparatorElem());
2140 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2141 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2142 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2143 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2145 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2149 Menu *cutnpaste_menu = manage (new Menu);
2150 MenuList& cutnpaste_items = cutnpaste_menu->items();
2151 cutnpaste_menu->set_name ("ArdourContextMenu");
2153 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2154 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2155 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2157 Menu *nudge_menu = manage (new Menu());
2158 MenuList& nudge_items = nudge_menu->items();
2159 nudge_menu->set_name ("ArdourContextMenu");
2161 edit_items.push_back (SeparatorElem());
2162 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2163 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2164 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2165 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2167 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2171 Editor::snap_type() const
2177 Editor::snap_musical() const
2179 switch (_snap_type) {
2180 case SnapToBeatDiv128:
2181 case SnapToBeatDiv64:
2182 case SnapToBeatDiv32:
2183 case SnapToBeatDiv28:
2184 case SnapToBeatDiv24:
2185 case SnapToBeatDiv20:
2186 case SnapToBeatDiv16:
2187 case SnapToBeatDiv14:
2188 case SnapToBeatDiv12:
2189 case SnapToBeatDiv10:
2190 case SnapToBeatDiv8:
2191 case SnapToBeatDiv7:
2192 case SnapToBeatDiv6:
2193 case SnapToBeatDiv5:
2194 case SnapToBeatDiv4:
2195 case SnapToBeatDiv3:
2196 case SnapToBeatDiv2:
2208 Editor::snap_mode() const
2214 Editor::set_snap_to (SnapType st)
2216 unsigned int snap_ind = (unsigned int)st;
2218 if (internal_editing()) {
2219 internal_snap_type = st;
2221 pre_internal_snap_type = st;
2226 if (snap_ind > snap_type_strings.size() - 1) {
2228 _snap_type = (SnapType)snap_ind;
2231 string str = snap_type_strings[snap_ind];
2233 if (str != snap_type_selector.get_text()) {
2234 snap_type_selector.set_text (str);
2239 switch (_snap_type) {
2240 case SnapToBeatDiv128:
2241 case SnapToBeatDiv64:
2242 case SnapToBeatDiv32:
2243 case SnapToBeatDiv28:
2244 case SnapToBeatDiv24:
2245 case SnapToBeatDiv20:
2246 case SnapToBeatDiv16:
2247 case SnapToBeatDiv14:
2248 case SnapToBeatDiv12:
2249 case SnapToBeatDiv10:
2250 case SnapToBeatDiv8:
2251 case SnapToBeatDiv7:
2252 case SnapToBeatDiv6:
2253 case SnapToBeatDiv5:
2254 case SnapToBeatDiv4:
2255 case SnapToBeatDiv3:
2256 case SnapToBeatDiv2: {
2257 std::vector<TempoMap::BBTPoint> grid;
2258 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
2259 compute_bbt_ruler_scale (grid, leftmost_frame, leftmost_frame + current_page_samples());
2260 update_tempo_based_rulers (grid);
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);
2354 Editor::set_state (const XMLNode& node, int version)
2356 XMLProperty const * prop;
2358 PBD::Unwinder<bool> nsi (no_save_instant, true);
2361 Tabbable::set_state (node, version);
2363 if (_session && (prop = node.property ("playhead"))) {
2365 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2367 playhead_cursor->set_position (pos);
2369 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2370 playhead_cursor->set_position (0);
2373 playhead_cursor->set_position (0);
2376 if ((prop = node.property ("mixer-width"))) {
2377 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2380 if ((prop = node.property ("zoom-focus"))) {
2381 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2383 zoom_focus_selection_done (zoom_focus);
2386 if ((prop = node.property ("zoom"))) {
2387 /* older versions of ardour used floating point samples_per_pixel */
2388 double f = PBD::atof (prop->value());
2389 reset_zoom (llrintf (f));
2391 reset_zoom (samples_per_pixel);
2394 if ((prop = node.property ("visible-track-count"))) {
2395 set_visible_track_count (PBD::atoi (prop->value()));
2398 if ((prop = node.property ("snap-to"))) {
2399 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2400 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2402 set_snap_to (_snap_type);
2405 if ((prop = node.property ("snap-mode"))) {
2406 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2407 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2408 * snap_mode_selection_done() will only mark an already active item as active
2409 * which does not trigger set_text().
2411 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2413 set_snap_mode (_snap_mode);
2416 if ((prop = node.property ("internal-snap-to"))) {
2417 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2420 if ((prop = node.property ("internal-snap-mode"))) {
2421 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2424 if ((prop = node.property ("pre-internal-snap-to"))) {
2425 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2428 if ((prop = node.property ("pre-internal-snap-mode"))) {
2429 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2432 if ((prop = node.property ("mouse-mode"))) {
2433 MouseMode m = str2mousemode(prop->value());
2434 set_mouse_mode (m, true);
2436 set_mouse_mode (MouseObject, true);
2439 if ((prop = node.property ("left-frame")) != 0) {
2441 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2445 reset_x_origin (pos);
2449 if ((prop = node.property ("y-origin")) != 0) {
2450 reset_y_origin (atof (prop->value ()));
2453 if ((prop = node.property ("join-object-range"))) {
2454 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2455 bool yn = string_is_affirmative (prop->value());
2457 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2458 tact->set_active (!yn);
2459 tact->set_active (yn);
2461 set_mouse_mode(mouse_mode, true);
2464 if ((prop = node.property ("edit-point"))) {
2465 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2467 set_edit_point_preference (_edit_point);
2470 if ((prop = node.property ("show-measures"))) {
2471 bool yn = string_is_affirmative (prop->value());
2472 _show_measures = yn;
2475 if ((prop = node.property ("follow-playhead"))) {
2476 bool yn = string_is_affirmative (prop->value());
2477 set_follow_playhead (yn);
2480 if ((prop = node.property ("stationary-playhead"))) {
2481 bool yn = string_is_affirmative (prop->value());
2482 set_stationary_playhead (yn);
2485 if ((prop = node.property ("region-list-sort-type"))) {
2486 RegionListSortType st;
2487 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2490 if ((prop = node.property ("show-editor-mixer"))) {
2492 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2495 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2496 bool yn = string_is_affirmative (prop->value());
2498 /* do it twice to force the change */
2500 tact->set_active (!yn);
2501 tact->set_active (yn);
2504 if ((prop = node.property ("show-editor-list"))) {
2506 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2509 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2510 bool yn = string_is_affirmative (prop->value());
2512 /* do it twice to force the change */
2514 tact->set_active (!yn);
2515 tact->set_active (yn);
2518 if ((prop = node.property (X_("editor-list-page")))) {
2519 _the_notebook.set_current_page (atoi (prop->value ()));
2522 if ((prop = node.property (X_("show-marker-lines")))) {
2523 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2525 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2526 bool yn = string_is_affirmative (prop->value ());
2528 tact->set_active (!yn);
2529 tact->set_active (yn);
2532 XMLNodeList children = node.children ();
2533 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2534 selection->set_state (**i, Stateful::current_state_version);
2535 _regions->set_state (**i);
2538 if ((prop = node.property ("maximised"))) {
2539 bool yn = string_is_affirmative (prop->value());
2540 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2542 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2543 bool fs = tact && tact->get_active();
2545 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2549 if ((prop = node.property ("nudge-clock-value"))) {
2551 sscanf (prop->value().c_str(), "%" PRId64, &f);
2552 nudge_clock->set (f);
2554 nudge_clock->set_mode (AudioClock::Timecode);
2555 nudge_clock->set (_session->frame_rate() * 5, true);
2560 * Not all properties may have been in XML, but
2561 * those that are linked to a private variable may need changing
2566 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2568 yn = _show_measures;
2569 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2570 /* do it twice to force the change */
2571 tact->set_active (!yn);
2572 tact->set_active (yn);
2575 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2576 yn = _follow_playhead;
2578 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2579 if (tact->get_active() != yn) {
2580 tact->set_active (yn);
2584 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2585 yn = _stationary_playhead;
2587 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2588 if (tact->get_active() != yn) {
2589 tact->set_active (yn);
2594 return LuaInstance::instance()->set_state(node);
2598 Editor::get_state ()
2600 XMLNode* node = new XMLNode (X_("Editor"));
2604 id().print (buf, sizeof (buf));
2605 node->add_property ("id", buf);
2607 node->add_child_nocopy (Tabbable::get_state());
2609 snprintf(buf,sizeof(buf), "%f", edit_pane.get_divider ());
2610 node->add_property("edit-horizontal-pane-pos", string(buf));
2611 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2612 snprintf(buf,sizeof(buf), "%f", editor_summary_pane.get_divider());
2613 node->add_property("edit-vertical-pane-pos", string(buf));
2615 maybe_add_mixer_strip_width (*node);
2617 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2619 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2620 node->add_property ("zoom", buf);
2621 node->add_property ("snap-to", enum_2_string (_snap_type));
2622 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2623 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2624 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2625 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2626 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2627 node->add_property ("edit-point", enum_2_string (_edit_point));
2628 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2629 node->add_property ("visible-track-count", buf);
2631 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2632 node->add_property ("playhead", buf);
2633 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2634 node->add_property ("left-frame", buf);
2635 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2636 node->add_property ("y-origin", buf);
2638 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2639 node->add_property ("maximised", _maximised ? "yes" : "no");
2640 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2641 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2642 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2643 node->add_property ("mouse-mode", enum2str(mouse_mode));
2644 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2646 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2648 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2649 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2652 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2654 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2655 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2658 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2659 node->add_property (X_("editor-list-page"), buf);
2661 if (button_bindings) {
2662 XMLNode* bb = new XMLNode (X_("Buttons"));
2663 button_bindings->save (*bb);
2664 node->add_child_nocopy (*bb);
2667 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2669 node->add_child_nocopy (selection->get_state ());
2670 node->add_child_nocopy (_regions->get_state ());
2672 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2673 node->add_property ("nudge-clock-value", buf);
2675 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2676 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2681 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2682 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2684 * @return pair: TimeAxisView that y is over, layer index.
2686 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2687 * in stacked or expanded region display mode, otherwise 0.
2689 std::pair<TimeAxisView *, double>
2690 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2692 if (!trackview_relative_offset) {
2693 y -= _trackview_group->canvas_origin().y;
2697 return std::make_pair ( (TimeAxisView *) 0, 0);
2700 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2702 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2709 return std::make_pair ( (TimeAxisView *) 0, 0);
2712 /** Snap a position to the grid, if appropriate, taking into account current
2713 * grid settings and also the state of any snap modifier keys that may be pressed.
2714 * @param start Position to snap.
2715 * @param event Event to get current key modifier information from, or 0.
2718 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2720 if (!_session || !event) {
2724 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2725 if (_snap_mode == SnapOff) {
2726 snap_to_internal (start, direction, for_mark);
2729 if (_snap_mode != SnapOff) {
2730 snap_to_internal (start, direction, for_mark);
2731 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2732 /* SnapOff, but we pressed the snap_delta modifier */
2733 snap_to_internal (start, direction, for_mark);
2739 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2741 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2745 snap_to_internal (start, direction, for_mark, ensure_snap);
2749 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2751 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2752 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2754 switch (_snap_type) {
2755 case SnapToTimecodeFrame:
2756 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2757 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2758 /* start is already on a whole timecode frame, do nothing */
2759 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2760 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2762 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2766 case SnapToTimecodeSeconds:
2767 if (_session->config.get_timecode_offset_negative()) {
2768 start += _session->config.get_timecode_offset ();
2770 start -= _session->config.get_timecode_offset ();
2772 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2773 (start % one_timecode_second == 0)) {
2774 /* start is already on a whole second, do nothing */
2775 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2776 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2778 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2781 if (_session->config.get_timecode_offset_negative()) {
2782 start -= _session->config.get_timecode_offset ();
2784 start += _session->config.get_timecode_offset ();
2788 case SnapToTimecodeMinutes:
2789 if (_session->config.get_timecode_offset_negative()) {
2790 start += _session->config.get_timecode_offset ();
2792 start -= _session->config.get_timecode_offset ();
2794 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2795 (start % one_timecode_minute == 0)) {
2796 /* start is already on a whole minute, do nothing */
2797 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2798 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2800 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2802 if (_session->config.get_timecode_offset_negative()) {
2803 start -= _session->config.get_timecode_offset ();
2805 start += _session->config.get_timecode_offset ();
2809 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2810 abort(); /*NOTREACHED*/
2815 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2817 const framepos_t one_second = _session->frame_rate();
2818 const framepos_t one_minute = _session->frame_rate() * 60;
2819 framepos_t presnap = start;
2823 switch (_snap_type) {
2824 case SnapToTimecodeFrame:
2825 case SnapToTimecodeSeconds:
2826 case SnapToTimecodeMinutes:
2827 return timecode_snap_to_internal (start, direction, for_mark);
2830 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2831 start % (one_second/75) == 0) {
2832 /* start is already on a whole CD frame, do nothing */
2833 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2834 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2836 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2841 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2842 start % one_second == 0) {
2843 /* start is already on a whole second, do nothing */
2844 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2845 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2847 start = (framepos_t) floor ((double) start / one_second) * one_second;
2852 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2853 start % one_minute == 0) {
2854 /* start is already on a whole minute, do nothing */
2855 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2856 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2858 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2863 start = _session->tempo_map().round_to_bar (start, direction);
2867 start = _session->tempo_map().round_to_beat (start, direction);
2870 case SnapToBeatDiv128:
2871 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2873 case SnapToBeatDiv64:
2874 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2876 case SnapToBeatDiv32:
2877 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2879 case SnapToBeatDiv28:
2880 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2882 case SnapToBeatDiv24:
2883 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2885 case SnapToBeatDiv20:
2886 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2888 case SnapToBeatDiv16:
2889 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2891 case SnapToBeatDiv14:
2892 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2894 case SnapToBeatDiv12:
2895 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2897 case SnapToBeatDiv10:
2898 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2900 case SnapToBeatDiv8:
2901 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2903 case SnapToBeatDiv7:
2904 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2906 case SnapToBeatDiv6:
2907 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2909 case SnapToBeatDiv5:
2910 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2912 case SnapToBeatDiv4:
2913 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2915 case SnapToBeatDiv3:
2916 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2918 case SnapToBeatDiv2:
2919 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2927 _session->locations()->marks_either_side (start, before, after);
2929 if (before == max_framepos && after == max_framepos) {
2930 /* No marks to snap to, so just don't snap */
2932 } else if (before == max_framepos) {
2934 } else if (after == max_framepos) {
2936 } else if (before != max_framepos && after != max_framepos) {
2937 /* have before and after */
2938 if ((start - before) < (after - start)) {
2947 case SnapToRegionStart:
2948 case SnapToRegionEnd:
2949 case SnapToRegionSync:
2950 case SnapToRegionBoundary:
2951 if (!region_boundary_cache.empty()) {
2953 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2954 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2956 if (direction > 0) {
2957 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2959 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2962 if (next != region_boundary_cache.begin ()) {
2967 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2968 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2970 if (start > (p + n) / 2) {
2979 switch (_snap_mode) {
2989 if (presnap > start) {
2990 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2994 } else if (presnap < start) {
2995 if (presnap < (start - pixel_to_sample(snap_threshold))) {
3001 /* handled at entry */
3009 Editor::setup_toolbar ()
3011 HBox* mode_box = manage(new HBox);
3012 mode_box->set_border_width (2);
3013 mode_box->set_spacing(2);
3015 HBox* mouse_mode_box = manage (new HBox);
3016 HBox* mouse_mode_hbox = manage (new HBox);
3017 VBox* mouse_mode_vbox = manage (new VBox);
3018 Alignment* mouse_mode_align = manage (new Alignment);
3020 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3021 mouse_mode_size_group->add_widget (smart_mode_button);
3022 mouse_mode_size_group->add_widget (mouse_move_button);
3023 mouse_mode_size_group->add_widget (mouse_cut_button);
3024 mouse_mode_size_group->add_widget (mouse_select_button);
3025 mouse_mode_size_group->add_widget (mouse_timefx_button);
3026 mouse_mode_size_group->add_widget (mouse_audition_button);
3027 mouse_mode_size_group->add_widget (mouse_draw_button);
3028 mouse_mode_size_group->add_widget (mouse_content_button);
3030 mouse_mode_size_group->add_widget (zoom_in_button);
3031 mouse_mode_size_group->add_widget (zoom_out_button);
3032 mouse_mode_size_group->add_widget (zoom_preset_selector);
3033 mouse_mode_size_group->add_widget (zoom_out_full_button);
3034 mouse_mode_size_group->add_widget (zoom_focus_selector);
3036 mouse_mode_size_group->add_widget (tav_shrink_button);
3037 mouse_mode_size_group->add_widget (tav_expand_button);
3038 mouse_mode_size_group->add_widget (visible_tracks_selector);
3040 mouse_mode_size_group->add_widget (snap_type_selector);
3041 mouse_mode_size_group->add_widget (snap_mode_selector);
3043 mouse_mode_size_group->add_widget (edit_point_selector);
3044 mouse_mode_size_group->add_widget (edit_mode_selector);
3046 mouse_mode_size_group->add_widget (*nudge_clock);
3047 mouse_mode_size_group->add_widget (nudge_forward_button);
3048 mouse_mode_size_group->add_widget (nudge_backward_button);
3050 mouse_mode_hbox->set_spacing (2);
3052 if (!ARDOUR::Profile->get_trx()) {
3053 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3056 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3057 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3059 if (!ARDOUR::Profile->get_mixbus()) {
3060 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3063 if (!ARDOUR::Profile->get_trx()) {
3064 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3065 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3066 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3067 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3070 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3072 mouse_mode_align->add (*mouse_mode_vbox);
3073 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3075 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3077 edit_mode_selector.set_name ("mouse mode button");
3079 if (!ARDOUR::Profile->get_trx()) {
3080 mode_box->pack_start (edit_mode_selector, false, false);
3083 mode_box->pack_start (*mouse_mode_box, false, false);
3087 _zoom_box.set_spacing (2);
3088 _zoom_box.set_border_width (2);
3092 zoom_preset_selector.set_name ("zoom button");
3093 zoom_preset_selector.set_image(::get_icon ("time_exp"));
3094 zoom_preset_selector.set_size_request (42, -1);
3096 zoom_in_button.set_name ("zoom button");
3097 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3098 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3099 zoom_in_button.set_related_action (act);
3101 zoom_out_button.set_name ("zoom button");
3102 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3103 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3104 zoom_out_button.set_related_action (act);
3106 zoom_out_full_button.set_name ("zoom button");
3107 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3108 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3109 zoom_out_full_button.set_related_action (act);
3111 zoom_focus_selector.set_name ("zoom button");
3113 if (ARDOUR::Profile->get_mixbus()) {
3114 _zoom_box.pack_start (zoom_preset_selector, false, false);
3115 } else if (ARDOUR::Profile->get_trx()) {
3116 mode_box->pack_start (zoom_out_button, false, false);
3117 mode_box->pack_start (zoom_in_button, false, false);
3119 _zoom_box.pack_start (zoom_out_button, false, false);
3120 _zoom_box.pack_start (zoom_in_button, false, false);
3121 _zoom_box.pack_start (zoom_out_full_button, false, false);
3122 _zoom_box.pack_start (zoom_focus_selector, false, false);
3125 /* Track zoom buttons */
3126 visible_tracks_selector.set_name ("zoom button");
3127 if (Profile->get_mixbus()) {
3128 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3129 visible_tracks_selector.set_size_request (42, -1);
3131 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3134 tav_expand_button.set_name ("zoom button");
3135 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3136 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3137 tav_expand_button.set_related_action (act);
3139 tav_shrink_button.set_name ("zoom button");
3140 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3141 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3142 tav_shrink_button.set_related_action (act);
3144 if (ARDOUR::Profile->get_mixbus()) {
3145 _zoom_box.pack_start (visible_tracks_selector);
3146 } else if (ARDOUR::Profile->get_trx()) {
3147 _zoom_box.pack_start (tav_shrink_button);
3148 _zoom_box.pack_start (tav_expand_button);
3150 _zoom_box.pack_start (visible_tracks_selector);
3151 _zoom_box.pack_start (tav_shrink_button);
3152 _zoom_box.pack_start (tav_expand_button);
3155 snap_box.set_spacing (2);
3156 snap_box.set_border_width (2);
3158 snap_type_selector.set_name ("mouse mode button");
3160 snap_mode_selector.set_name ("mouse mode button");
3162 edit_point_selector.set_name ("mouse mode button");
3164 snap_box.pack_start (snap_mode_selector, false, false);
3165 snap_box.pack_start (snap_type_selector, false, false);
3166 snap_box.pack_start (edit_point_selector, false, false);
3170 HBox *nudge_box = manage (new HBox);
3171 nudge_box->set_spacing (2);
3172 nudge_box->set_border_width (2);
3174 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3175 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3177 nudge_box->pack_start (nudge_backward_button, false, false);
3178 nudge_box->pack_start (nudge_forward_button, false, false);
3179 nudge_box->pack_start (*nudge_clock, false, false);
3182 /* Pack everything in... */
3184 HBox* hbox = manage (new HBox);
3185 hbox->set_spacing(2);
3187 toolbar_hbox.set_spacing (2);
3188 toolbar_hbox.set_border_width (1);
3190 toolbar_hbox.pack_start (*mode_box, false, false);
3191 if (!ARDOUR::Profile->get_trx()) {
3192 toolbar_hbox.pack_start (_zoom_box, false, false);
3193 toolbar_hbox.pack_start (*hbox, false, false);
3196 if (!ARDOUR::Profile->get_trx()) {
3197 hbox->pack_start (snap_box, false, false);
3198 hbox->pack_start (*nudge_box, false, false);
3203 toolbar_base.set_name ("ToolBarBase");
3204 toolbar_base.add (toolbar_hbox);
3206 _toolbar_viewport.add (toolbar_base);
3207 /* stick to the required height but allow width to vary if there's not enough room */
3208 _toolbar_viewport.set_size_request (1, -1);
3210 toolbar_frame.set_shadow_type (SHADOW_OUT);
3211 toolbar_frame.set_name ("BaseFrame");
3212 toolbar_frame.add (_toolbar_viewport);
3216 Editor::build_edit_point_menu ()
3218 using namespace Menu_Helpers;
3220 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3221 if(!Profile->get_mixbus())
3222 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3223 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3225 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3229 Editor::build_edit_mode_menu ()
3231 using namespace Menu_Helpers;
3233 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3234 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3235 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3236 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3238 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3242 Editor::build_snap_mode_menu ()
3244 using namespace Menu_Helpers;
3246 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3247 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3248 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3250 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3254 Editor::build_snap_type_menu ()
3256 using namespace Menu_Helpers;
3258 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3259 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3260 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3261 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3262 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3263 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3264 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3265 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3266 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3267 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3268 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3269 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3270 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3271 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3272 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3273 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3274 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3275 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3276 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3277 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3278 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3279 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3280 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3281 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3282 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3283 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3284 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3285 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3286 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3287 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3289 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3294 Editor::setup_tooltips ()
3296 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3297 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3298 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3299 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3300 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3301 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3302 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3303 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3304 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3305 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3306 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3307 set_tooltip (zoom_in_button, _("Zoom In"));
3308 set_tooltip (zoom_out_button, _("Zoom Out"));
3309 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3310 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3311 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3312 set_tooltip (tav_expand_button, _("Expand Tracks"));
3313 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3314 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3315 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3316 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3317 set_tooltip (edit_point_selector, _("Edit Point"));
3318 set_tooltip (edit_mode_selector, _("Edit Mode"));
3319 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3323 Editor::convert_drop_to_paths (
3324 vector<string>& paths,
3325 const RefPtr<Gdk::DragContext>& /*context*/,
3328 const SelectionData& data,
3332 if (_session == 0) {
3336 vector<string> uris = data.get_uris();
3340 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3341 are actually URI lists. So do it by hand.
3344 if (data.get_target() != "text/plain") {
3348 /* Parse the "uri-list" format that Nautilus provides,
3349 where each pathname is delimited by \r\n.
3351 THERE MAY BE NO NULL TERMINATING CHAR!!!
3354 string txt = data.get_text();
3358 p = (char *) malloc (txt.length() + 1);
3359 txt.copy (p, txt.length(), 0);
3360 p[txt.length()] = '\0';
3366 while (g_ascii_isspace (*p))
3370 while (*q && (*q != '\n') && (*q != '\r')) {
3377 while (q > p && g_ascii_isspace (*q))
3382 uris.push_back (string (p, q - p + 1));
3386 p = strchr (p, '\n');
3398 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3399 if ((*i).substr (0,7) == "file://") {
3400 paths.push_back (Glib::filename_from_uri (*i));
3408 Editor::new_tempo_section ()
3413 Editor::map_transport_state ()
3415 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3417 if (_session && _session->transport_stopped()) {
3418 have_pending_keyboard_selection = false;
3421 update_loop_range_view ();
3427 Editor::begin_selection_op_history ()
3429 selection_op_cmd_depth = 0;
3430 selection_op_history_it = 0;
3432 while(!selection_op_history.empty()) {
3433 delete selection_op_history.front();
3434 selection_op_history.pop_front();
3437 selection_undo_action->set_sensitive (false);
3438 selection_redo_action->set_sensitive (false);
3439 selection_op_history.push_front (&_selection_memento->get_state ());
3443 Editor::begin_reversible_selection_op (string name)
3446 //cerr << name << endl;
3447 /* begin/commit pairs can be nested */
3448 selection_op_cmd_depth++;
3453 Editor::commit_reversible_selection_op ()
3456 if (selection_op_cmd_depth == 1) {
3458 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3460 The user has undone some selection ops and then made a new one,
3461 making anything earlier in the list invalid.
3464 list<XMLNode *>::iterator it = selection_op_history.begin();
3465 list<XMLNode *>::iterator e_it = it;
3466 advance (e_it, selection_op_history_it);
3468 for ( ; it != e_it; ++it) {
3471 selection_op_history.erase (selection_op_history.begin(), e_it);
3474 selection_op_history.push_front (&_selection_memento->get_state ());
3475 selection_op_history_it = 0;
3477 selection_undo_action->set_sensitive (true);
3478 selection_redo_action->set_sensitive (false);
3481 if (selection_op_cmd_depth > 0) {
3482 selection_op_cmd_depth--;
3488 Editor::undo_selection_op ()
3491 selection_op_history_it++;
3493 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3494 if (n == selection_op_history_it) {
3495 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3496 selection_redo_action->set_sensitive (true);
3500 /* is there an earlier entry? */
3501 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3502 selection_undo_action->set_sensitive (false);
3508 Editor::redo_selection_op ()
3511 if (selection_op_history_it > 0) {
3512 selection_op_history_it--;
3515 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3516 if (n == selection_op_history_it) {
3517 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3518 selection_undo_action->set_sensitive (true);
3523 if (selection_op_history_it == 0) {
3524 selection_redo_action->set_sensitive (false);
3530 Editor::begin_reversible_command (string name)
3533 before.push_back (&_selection_memento->get_state ());
3534 _session->begin_reversible_command (name);
3539 Editor::begin_reversible_command (GQuark q)
3542 before.push_back (&_selection_memento->get_state ());
3543 _session->begin_reversible_command (q);
3548 Editor::abort_reversible_command ()
3551 while(!before.empty()) {
3552 delete before.front();
3555 _session->abort_reversible_command ();
3560 Editor::commit_reversible_command ()
3563 if (before.size() == 1) {
3564 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3565 redo_action->set_sensitive(false);
3566 undo_action->set_sensitive(true);
3567 begin_selection_op_history ();
3570 if (before.empty()) {
3571 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3576 _session->commit_reversible_command ();
3581 Editor::history_changed ()
3585 if (undo_action && _session) {
3586 if (_session->undo_depth() == 0) {
3587 label = S_("Command|Undo");
3589 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3591 undo_action->property_label() = label;
3594 if (redo_action && _session) {
3595 if (_session->redo_depth() == 0) {
3597 redo_action->set_sensitive (false);
3599 label = string_compose(_("Redo (%1)"), _session->next_redo());
3600 redo_action->set_sensitive (true);
3602 redo_action->property_label() = label;
3607 Editor::duplicate_range (bool with_dialog)
3611 RegionSelection rs = get_regions_from_selection_and_entered ();
3613 if ( selection->time.length() == 0 && rs.empty()) {
3619 ArdourDialog win (_("Duplicate"));
3620 Label label (_("Number of duplications:"));
3621 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3622 SpinButton spinner (adjustment, 0.0, 1);
3625 win.get_vbox()->set_spacing (12);
3626 win.get_vbox()->pack_start (hbox);
3627 hbox.set_border_width (6);
3628 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3630 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3631 place, visually. so do this by hand.
3634 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3635 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3636 spinner.grab_focus();
3642 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3643 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3644 win.set_default_response (RESPONSE_ACCEPT);
3646 spinner.grab_focus ();
3648 switch (win.run ()) {
3649 case RESPONSE_ACCEPT:
3655 times = adjustment.get_value();
3658 if ((current_mouse_mode() == Editing::MouseRange)) {
3659 if (selection->time.length()) {
3660 duplicate_selection (times);
3662 } else if (get_smart_mode()) {
3663 if (selection->time.length()) {
3664 duplicate_selection (times);
3666 duplicate_some_regions (rs, times);
3668 duplicate_some_regions (rs, times);
3673 Editor::set_edit_mode (EditMode m)
3675 Config->set_edit_mode (m);
3679 Editor::cycle_edit_mode ()
3681 switch (Config->get_edit_mode()) {
3683 Config->set_edit_mode (Ripple);
3687 Config->set_edit_mode (Lock);
3690 Config->set_edit_mode (Slide);
3696 Editor::edit_mode_selection_done ( EditMode m )
3698 Config->set_edit_mode ( m );
3702 Editor::snap_type_selection_done (SnapType snaptype)
3704 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3706 ract->set_active ();
3711 Editor::snap_mode_selection_done (SnapMode mode)
3713 RefPtr<RadioAction> ract = snap_mode_action (mode);
3716 ract->set_active (true);
3721 Editor::cycle_edit_point (bool with_marker)
3723 if(Profile->get_mixbus())
3724 with_marker = false;
3726 switch (_edit_point) {
3728 set_edit_point_preference (EditAtPlayhead);
3730 case EditAtPlayhead:
3732 set_edit_point_preference (EditAtSelectedMarker);
3734 set_edit_point_preference (EditAtMouse);
3737 case EditAtSelectedMarker:
3738 set_edit_point_preference (EditAtMouse);
3744 Editor::edit_point_selection_done (EditPoint ep)
3746 set_edit_point_preference ( ep );
3750 Editor::build_zoom_focus_menu ()
3752 using namespace Menu_Helpers;
3754 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3755 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3756 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3757 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3758 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3759 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3761 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3765 Editor::zoom_focus_selection_done ( ZoomFocus f )
3767 RefPtr<RadioAction> ract = zoom_focus_action (f);
3769 ract->set_active ();
3774 Editor::build_track_count_menu ()
3776 using namespace Menu_Helpers;
3778 if (!Profile->get_mixbus()) {
3779 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3780 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3781 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3782 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3783 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3784 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3785 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3786 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3787 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3788 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3789 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3790 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3791 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3793 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3794 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3795 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3796 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3797 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3798 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3799 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3800 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3801 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3802 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3804 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3805 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3806 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3807 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3808 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3809 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3810 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3811 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3812 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3813 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3814 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3819 Editor::set_zoom_preset (int64_t ms)
3822 temporal_zoom_session();
3826 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3827 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3831 Editor::set_visible_track_count (int32_t n)
3833 _visible_track_count = n;
3835 /* if the canvas hasn't really been allocated any size yet, just
3836 record the desired number of visible tracks and return. when canvas
3837 allocation happens, we will get called again and then we can do the
3841 if (_visible_canvas_height <= 1) {
3847 DisplaySuspender ds;
3849 if (_visible_track_count > 0) {
3850 h = trackviews_height() / _visible_track_count;
3851 std::ostringstream s;
3852 s << _visible_track_count;
3854 } else if (_visible_track_count == 0) {
3856 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3857 if ((*i)->marked_for_display()) {
3861 h = trackviews_height() / n;
3864 /* negative value means that the visible track count has
3865 been overridden by explicit track height changes.
3867 visible_tracks_selector.set_text (X_("*"));
3871 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3872 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3875 if (str != visible_tracks_selector.get_text()) {
3876 visible_tracks_selector.set_text (str);
3881 Editor::override_visible_track_count ()
3883 _visible_track_count = -1;
3884 visible_tracks_selector.set_text ( _("*") );
3888 Editor::edit_controls_button_release (GdkEventButton* ev)
3890 if (Keyboard::is_context_menu_event (ev)) {
3891 ARDOUR_UI::instance()->add_route ();
3892 } else if (ev->button == 1) {
3893 selection->clear_tracks ();
3900 Editor::mouse_select_button_release (GdkEventButton* ev)
3902 /* this handles just right-clicks */
3904 if (ev->button != 3) {
3912 Editor::set_zoom_focus (ZoomFocus f)
3914 string str = zoom_focus_strings[(int)f];
3916 if (str != zoom_focus_selector.get_text()) {
3917 zoom_focus_selector.set_text (str);
3920 if (zoom_focus != f) {
3927 Editor::cycle_zoom_focus ()
3929 switch (zoom_focus) {
3931 set_zoom_focus (ZoomFocusRight);
3933 case ZoomFocusRight:
3934 set_zoom_focus (ZoomFocusCenter);
3936 case ZoomFocusCenter:
3937 set_zoom_focus (ZoomFocusPlayhead);
3939 case ZoomFocusPlayhead:
3940 set_zoom_focus (ZoomFocusMouse);
3942 case ZoomFocusMouse:
3943 set_zoom_focus (ZoomFocusEdit);
3946 set_zoom_focus (ZoomFocusLeft);
3952 Editor::set_show_measures (bool yn)
3954 if (_show_measures != yn) {
3957 if ((_show_measures = yn) == true) {
3959 tempo_lines->show();
3962 std::vector<TempoMap::BBTPoint> grid;
3963 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3964 draw_measures (grid);
3972 Editor::toggle_follow_playhead ()
3974 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3976 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3977 set_follow_playhead (tact->get_active());
3981 /** @param yn true to follow playhead, otherwise false.
3982 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3985 Editor::set_follow_playhead (bool yn, bool catch_up)
3987 if (_follow_playhead != yn) {
3988 if ((_follow_playhead = yn) == true && catch_up) {
3990 reset_x_origin_to_follow_playhead ();
3997 Editor::toggle_stationary_playhead ()
3999 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4001 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4002 set_stationary_playhead (tact->get_active());
4007 Editor::set_stationary_playhead (bool yn)
4009 if (_stationary_playhead != yn) {
4010 if ((_stationary_playhead = yn) == true) {
4012 // FIXME need a 3.0 equivalent of this 2.X call
4013 // update_current_screen ();
4020 Editor::playlist_selector () const
4022 return *_playlist_selector;
4026 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4028 if (paste_count == 0) {
4029 /* don't bother calculating an offset that will be zero anyway */
4033 /* calculate basic unsnapped multi-paste offset */
4034 framecnt_t offset = paste_count * duration;
4036 /* snap offset so pos + offset is aligned to the grid */
4037 framepos_t offset_pos = pos + offset;
4038 snap_to(offset_pos, RoundUpMaybe);
4039 offset = offset_pos - pos;
4045 Editor::get_grid_beat_divisions(framepos_t position)
4047 switch (_snap_type) {
4048 case SnapToBeatDiv128: return 128;
4049 case SnapToBeatDiv64: return 64;
4050 case SnapToBeatDiv32: return 32;
4051 case SnapToBeatDiv28: return 28;
4052 case SnapToBeatDiv24: return 24;
4053 case SnapToBeatDiv20: return 20;
4054 case SnapToBeatDiv16: return 16;
4055 case SnapToBeatDiv14: return 14;
4056 case SnapToBeatDiv12: return 12;
4057 case SnapToBeatDiv10: return 10;
4058 case SnapToBeatDiv8: return 8;
4059 case SnapToBeatDiv7: return 7;
4060 case SnapToBeatDiv6: return 6;
4061 case SnapToBeatDiv5: return 5;
4062 case SnapToBeatDiv4: return 4;
4063 case SnapToBeatDiv3: return 3;
4064 case SnapToBeatDiv2: return 2;
4070 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4071 if the grid is non-musical, returns 0.
4072 if the grid is snapped to bars, returns -1.
4073 @param event_state the current keyboard modifier mask.
4076 Editor::get_grid_music_divisions (uint32_t event_state)
4078 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4082 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4086 switch (_snap_type) {
4087 case SnapToBeatDiv128: return 128;
4088 case SnapToBeatDiv64: return 64;
4089 case SnapToBeatDiv32: return 32;
4090 case SnapToBeatDiv28: return 28;
4091 case SnapToBeatDiv24: return 24;
4092 case SnapToBeatDiv20: return 20;
4093 case SnapToBeatDiv16: return 16;
4094 case SnapToBeatDiv14: return 14;
4095 case SnapToBeatDiv12: return 12;
4096 case SnapToBeatDiv10: return 10;
4097 case SnapToBeatDiv8: return 8;
4098 case SnapToBeatDiv7: return 7;
4099 case SnapToBeatDiv6: return 6;
4100 case SnapToBeatDiv5: return 5;
4101 case SnapToBeatDiv4: return 4;
4102 case SnapToBeatDiv3: return 3;
4103 case SnapToBeatDiv2: return 2;
4104 case SnapToBeat: return 1;
4105 case SnapToBar : return -1;
4112 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4116 const unsigned divisions = get_grid_beat_divisions(position);
4118 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4121 switch (_snap_type) {
4123 return Evoral::Beats(1.0);
4126 return Evoral::Beats(_session->tempo_map().meter_at_frame (position).divisions_per_bar());
4134 return Evoral::Beats();
4138 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4142 ret = nudge_clock->current_duration (pos);
4143 next = ret + 1; /* XXXX fix me */
4149 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4151 ArdourDialog dialog (_("Playlist Deletion"));
4152 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4153 "If it is kept, its audio files will not be cleaned.\n"
4154 "If it is deleted, audio files used by it alone will be cleaned."),
4157 dialog.set_position (WIN_POS_CENTER);
4158 dialog.get_vbox()->pack_start (label);
4162 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4163 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4164 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4165 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4166 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4168 // by default gtk uses the left most button
4169 keep->grab_focus ();
4171 switch (dialog.run ()) {
4173 /* keep this and all remaining ones */
4178 /* delete this and all others */
4182 case RESPONSE_ACCEPT:
4183 /* delete the playlist */
4187 case RESPONSE_REJECT:
4188 /* keep the playlist */
4200 Editor::audio_region_selection_covers (framepos_t where)
4202 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4203 if ((*a)->region()->covers (where)) {
4212 Editor::prepare_for_cleanup ()
4214 cut_buffer->clear_regions ();
4215 cut_buffer->clear_playlists ();
4217 selection->clear_regions ();
4218 selection->clear_playlists ();
4220 _regions->suspend_redisplay ();
4224 Editor::finish_cleanup ()
4226 _regions->resume_redisplay ();
4230 Editor::transport_loop_location()
4233 return _session->locations()->auto_loop_location();
4240 Editor::transport_punch_location()
4243 return _session->locations()->auto_punch_location();
4250 Editor::control_layout_scroll (GdkEventScroll* ev)
4252 /* Just forward to the normal canvas scroll method. The coordinate
4253 systems are different but since the canvas is always larger than the
4254 track headers, and aligned with the trackview area, this will work.
4256 In the not too distant future this layout is going away anyway and
4257 headers will be on the canvas.
4259 return canvas_scroll_event (ev, false);
4263 Editor::session_state_saved (string)
4266 _snapshots->redisplay ();
4270 Editor::maximise_editing_space ()
4276 Gtk::Window* toplevel = current_toplevel();
4279 toplevel->fullscreen ();
4285 Editor::restore_editing_space ()
4291 Gtk::Window* toplevel = current_toplevel();
4294 toplevel->unfullscreen();
4300 * Make new playlists for a given track and also any others that belong
4301 * to the same active route group with the `select' property.
4306 Editor::new_playlists (TimeAxisView* v)
4308 begin_reversible_command (_("new playlists"));
4309 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4310 _session->playlists->get (playlists);
4311 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4312 commit_reversible_command ();
4316 * Use a copy of the current playlist for a given track and also any others that belong
4317 * to the same active route group with the `select' property.
4322 Editor::copy_playlists (TimeAxisView* v)
4324 begin_reversible_command (_("copy playlists"));
4325 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4326 _session->playlists->get (playlists);
4327 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4328 commit_reversible_command ();
4331 /** Clear the current playlist for a given track and also any others that belong
4332 * to the same active route group with the `select' property.
4337 Editor::clear_playlists (TimeAxisView* v)
4339 begin_reversible_command (_("clear playlists"));
4340 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4341 _session->playlists->get (playlists);
4342 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4343 commit_reversible_command ();
4347 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4349 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4353 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4355 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4359 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4361 atv.clear_playlist ();
4365 Editor::get_y_origin () const
4367 return vertical_adjustment.get_value ();
4370 /** Queue up a change to the viewport x origin.
4371 * @param frame New x origin.
4374 Editor::reset_x_origin (framepos_t frame)
4376 pending_visual_change.add (VisualChange::TimeOrigin);
4377 pending_visual_change.time_origin = frame;
4378 ensure_visual_change_idle_handler ();
4382 Editor::reset_y_origin (double y)
4384 pending_visual_change.add (VisualChange::YOrigin);
4385 pending_visual_change.y_origin = y;
4386 ensure_visual_change_idle_handler ();
4390 Editor::reset_zoom (framecnt_t spp)
4392 if (spp == samples_per_pixel) {
4396 pending_visual_change.add (VisualChange::ZoomLevel);
4397 pending_visual_change.samples_per_pixel = spp;
4398 ensure_visual_change_idle_handler ();
4402 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4404 reset_x_origin (frame);
4407 if (!no_save_visual) {
4408 undo_visual_stack.push_back (current_visual_state(false));
4412 Editor::VisualState::VisualState (bool with_tracks)
4413 : gui_state (with_tracks ? new GUIObjectState : 0)
4417 Editor::VisualState::~VisualState ()
4422 Editor::VisualState*
4423 Editor::current_visual_state (bool with_tracks)
4425 VisualState* vs = new VisualState (with_tracks);
4426 vs->y_position = vertical_adjustment.get_value();
4427 vs->samples_per_pixel = samples_per_pixel;
4428 vs->leftmost_frame = leftmost_frame;
4429 vs->zoom_focus = zoom_focus;
4432 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4439 Editor::undo_visual_state ()
4441 if (undo_visual_stack.empty()) {
4445 VisualState* vs = undo_visual_stack.back();
4446 undo_visual_stack.pop_back();
4449 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4452 use_visual_state (*vs);
4457 Editor::redo_visual_state ()
4459 if (redo_visual_stack.empty()) {
4463 VisualState* vs = redo_visual_stack.back();
4464 redo_visual_stack.pop_back();
4466 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4467 // why do we check here?
4468 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4471 use_visual_state (*vs);
4476 Editor::swap_visual_state ()
4478 if (undo_visual_stack.empty()) {
4479 redo_visual_state ();
4481 undo_visual_state ();
4486 Editor::use_visual_state (VisualState& vs)
4488 PBD::Unwinder<bool> nsv (no_save_visual, true);
4489 DisplaySuspender ds;
4491 vertical_adjustment.set_value (vs.y_position);
4493 set_zoom_focus (vs.zoom_focus);
4494 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4497 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4499 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4500 (*i)->clear_property_cache();
4501 (*i)->reset_visual_state ();
4505 _routes->update_visibility ();
4508 /** This is the core function that controls the zoom level of the canvas. It is called
4509 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4510 * @param spp new number of samples per pixel
4513 Editor::set_samples_per_pixel (framecnt_t spp)
4519 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4520 const framecnt_t lots_of_pixels = 4000;
4522 /* if the zoom level is greater than what you'd get trying to display 3
4523 * days of audio on a really big screen, then it's too big.
4526 if (spp * lots_of_pixels > three_days) {
4530 samples_per_pixel = spp;
4533 tempo_lines->tempo_map_changed();
4536 bool const showing_time_selection = selection->time.length() > 0;
4538 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4539 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4540 (*i)->reshow_selection (selection->time);
4544 ZoomChanged (); /* EMIT_SIGNAL */
4546 ArdourCanvas::GtkCanvasViewport* c;
4548 c = get_track_canvas();
4550 c->canvas()->zoomed ();
4553 if (playhead_cursor) {
4554 playhead_cursor->set_position (playhead_cursor->current_frame ());
4557 refresh_location_display();
4558 _summary->set_overlays_dirty ();
4560 update_marker_labels ();
4566 Editor::queue_visual_videotimeline_update ()
4569 * pending_visual_change.add (VisualChange::VideoTimeline);
4570 * or maybe even more specific: which videotimeline-image
4571 * currently it calls update_video_timeline() to update
4572 * _all outdated_ images on the video-timeline.
4573 * see 'exposeimg()' in video_image_frame.cc
4575 ensure_visual_change_idle_handler ();
4579 Editor::ensure_visual_change_idle_handler ()
4581 if (pending_visual_change.idle_handler_id < 0) {
4582 // see comment in add_to_idle_resize above.
4583 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4584 pending_visual_change.being_handled = false;
4589 Editor::_idle_visual_changer (void* arg)
4591 return static_cast<Editor*>(arg)->idle_visual_changer ();
4595 Editor::idle_visual_changer ()
4597 /* set_horizontal_position() below (and maybe other calls) call
4598 gtk_main_iteration(), so it's possible that a signal will be handled
4599 half-way through this method. If this signal wants an
4600 idle_visual_changer we must schedule another one after this one, so
4601 mark the idle_handler_id as -1 here to allow that. Also make a note
4602 that we are doing the visual change, so that changes in response to
4603 super-rapid-screen-update can be dropped if we are still processing
4607 pending_visual_change.idle_handler_id = -1;
4608 pending_visual_change.being_handled = true;
4610 VisualChange vc = pending_visual_change;
4612 pending_visual_change.pending = (VisualChange::Type) 0;
4614 visual_changer (vc);
4616 pending_visual_change.being_handled = false;
4618 return 0; /* this is always a one-shot call */
4622 Editor::visual_changer (const VisualChange& vc)
4624 double const last_time_origin = horizontal_position ();
4626 if (vc.pending & VisualChange::ZoomLevel) {
4627 set_samples_per_pixel (vc.samples_per_pixel);
4629 compute_fixed_ruler_scale ();
4631 std::vector<TempoMap::BBTPoint> grid;
4632 compute_current_bbt_points (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4633 compute_bbt_ruler_scale (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4634 update_tempo_based_rulers (grid);
4636 update_video_timeline();
4639 if (vc.pending & VisualChange::TimeOrigin) {
4640 set_horizontal_position (vc.time_origin / samples_per_pixel);
4643 if (vc.pending & VisualChange::YOrigin) {
4644 vertical_adjustment.set_value (vc.y_origin);
4647 if (last_time_origin == horizontal_position ()) {
4648 /* changed signal not emitted */
4649 update_fixed_rulers ();
4650 redisplay_tempo (true);
4653 if (!(vc.pending & VisualChange::ZoomLevel)) {
4654 update_video_timeline();
4657 _summary->set_overlays_dirty ();
4660 struct EditorOrderTimeAxisSorter {
4661 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4662 return a->order () < b->order ();
4667 Editor::sort_track_selection (TrackViewList& sel)
4669 EditorOrderTimeAxisSorter cmp;
4674 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4677 framepos_t where = 0;
4678 EditPoint ep = _edit_point;
4680 if (Profile->get_mixbus())
4681 if (ep == EditAtSelectedMarker)
4682 ep = EditAtPlayhead;
4684 if (from_outside_canvas && (ep == EditAtMouse)) {
4685 ep = EditAtPlayhead;
4686 } else if (from_context_menu && (ep == EditAtMouse)) {
4687 return canvas_event_sample (&context_click_event, 0, 0);
4690 if (entered_marker) {
4691 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4692 return entered_marker->position();
4695 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4696 ep = EditAtSelectedMarker;
4699 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4700 ep = EditAtPlayhead;
4704 case EditAtPlayhead:
4705 if (_dragging_playhead) {
4706 where = *_control_scroll_target;
4708 where = _session->audible_frame();
4710 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4713 case EditAtSelectedMarker:
4714 if (!selection->markers.empty()) {
4716 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4719 where = loc->start();
4723 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4731 if (!mouse_frame (where, ignored)) {
4732 /* XXX not right but what can we do ? */
4736 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4744 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4746 if (!_session) return;
4748 begin_reversible_command (cmd);
4752 if ((tll = transport_loop_location()) == 0) {
4753 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4754 XMLNode &before = _session->locations()->get_state();
4755 _session->locations()->add (loc, true);
4756 _session->set_auto_loop_location (loc);
4757 XMLNode &after = _session->locations()->get_state();
4758 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4760 XMLNode &before = tll->get_state();
4761 tll->set_hidden (false, this);
4762 tll->set (start, end);
4763 XMLNode &after = tll->get_state();
4764 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4767 commit_reversible_command ();
4771 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4773 if (!_session) return;
4775 begin_reversible_command (cmd);
4779 if ((tpl = transport_punch_location()) == 0) {
4780 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4781 XMLNode &before = _session->locations()->get_state();
4782 _session->locations()->add (loc, true);
4783 _session->set_auto_punch_location (loc);
4784 XMLNode &after = _session->locations()->get_state();
4785 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4787 XMLNode &before = tpl->get_state();
4788 tpl->set_hidden (false, this);
4789 tpl->set (start, end);
4790 XMLNode &after = tpl->get_state();
4791 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4794 commit_reversible_command ();
4797 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4798 * @param rs List to which found regions are added.
4799 * @param where Time to look at.
4800 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4803 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4805 const TrackViewList* tracks;
4808 tracks = &track_views;
4813 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4815 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4818 boost::shared_ptr<Track> tr;
4819 boost::shared_ptr<Playlist> pl;
4821 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4823 boost::shared_ptr<RegionList> regions = pl->regions_at (
4824 (framepos_t) floor ( (double) where * tr->speed()));
4826 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4827 RegionView* rv = rtv->view()->find_view (*i);
4838 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4840 const TrackViewList* tracks;
4843 tracks = &track_views;
4848 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4849 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4851 boost::shared_ptr<Track> tr;
4852 boost::shared_ptr<Playlist> pl;
4854 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4856 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4857 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4859 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4861 RegionView* rv = rtv->view()->find_view (*i);
4872 /** Get regions using the following method:
4874 * Make a region list using:
4875 * (a) any selected regions
4876 * (b) the intersection of any selected tracks and the edit point(*)
4877 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4879 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4881 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4885 Editor::get_regions_from_selection_and_edit_point ()
4887 RegionSelection regions;
4889 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4890 regions.add (entered_regionview);
4892 regions = selection->regions;
4895 if ( regions.empty() ) {
4896 TrackViewList tracks = selection->tracks;
4898 if (!tracks.empty()) {
4899 /* no region selected or entered, but some selected tracks:
4900 * act on all regions on the selected tracks at the edit point
4902 framepos_t const where = get_preferred_edit_position ();
4903 get_regions_at(regions, where, tracks);
4910 /** Get regions using the following method:
4912 * Make a region list using:
4913 * (a) any selected regions
4914 * (b) the intersection of any selected tracks and the edit point(*)
4915 * (c) if neither exists, then whatever region is under the mouse
4917 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4919 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4922 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4924 RegionSelection regions;
4926 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4927 regions.add (entered_regionview);
4929 regions = selection->regions;
4932 if ( regions.empty() ) {
4933 TrackViewList tracks = selection->tracks;
4935 if (!tracks.empty()) {
4936 /* no region selected or entered, but some selected tracks:
4937 * act on all regions on the selected tracks at the edit point
4939 get_regions_at(regions, pos, tracks);
4946 /** Start with regions that are selected, or the entered regionview if none are selected.
4947 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4948 * of the regions that we started with.
4952 Editor::get_regions_from_selection_and_entered () const
4954 RegionSelection regions = selection->regions;
4956 if (regions.empty() && entered_regionview) {
4957 regions.add (entered_regionview);
4964 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4966 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4967 RouteTimeAxisView* rtav;
4969 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4970 boost::shared_ptr<Playlist> pl;
4971 std::vector<boost::shared_ptr<Region> > results;
4972 boost::shared_ptr<Track> tr;
4974 if ((tr = rtav->track()) == 0) {
4979 if ((pl = (tr->playlist())) != 0) {
4980 boost::shared_ptr<Region> r = pl->region_by_id (id);
4982 RegionView* rv = rtav->view()->find_view (r);
4984 regions.push_back (rv);
4993 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4996 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4997 MidiTimeAxisView* mtav;
4999 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5001 mtav->get_per_region_note_selection (selection);
5008 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5010 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5012 RouteTimeAxisView* tatv;
5014 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5016 boost::shared_ptr<Playlist> pl;
5017 vector<boost::shared_ptr<Region> > results;
5019 boost::shared_ptr<Track> tr;
5021 if ((tr = tatv->track()) == 0) {
5026 if ((pl = (tr->playlist())) != 0) {
5027 if (src_comparison) {
5028 pl->get_source_equivalent_regions (region, results);
5030 pl->get_region_list_equivalent_regions (region, results);
5034 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5035 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5036 regions.push_back (marv);
5045 Editor::show_rhythm_ferret ()
5047 if (rhythm_ferret == 0) {
5048 rhythm_ferret = new RhythmFerret(*this);
5051 rhythm_ferret->set_session (_session);
5052 rhythm_ferret->show ();
5053 rhythm_ferret->present ();
5057 Editor::first_idle ()
5059 MessageDialog* dialog = 0;
5061 if (track_views.size() > 1) {
5062 Timers::TimerSuspender t;
5063 dialog = new MessageDialog (
5064 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5068 ARDOUR_UI::instance()->flush_pending ();
5071 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5075 // first idle adds route children (automation tracks), so we need to redisplay here
5076 _routes->redisplay ();
5080 if (_session->undo_depth() == 0) {
5081 undo_action->set_sensitive(false);
5083 redo_action->set_sensitive(false);
5084 begin_selection_op_history ();
5090 Editor::_idle_resize (gpointer arg)
5092 return ((Editor*)arg)->idle_resize ();
5096 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5098 if (resize_idle_id < 0) {
5099 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5100 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5101 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5103 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5104 _pending_resize_amount = 0;
5107 /* make a note of the smallest resulting height, so that we can clamp the
5108 lower limit at TimeAxisView::hSmall */
5110 int32_t min_resulting = INT32_MAX;
5112 _pending_resize_amount += h;
5113 _pending_resize_view = view;
5115 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5117 if (selection->tracks.contains (_pending_resize_view)) {
5118 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5119 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5123 if (min_resulting < 0) {
5128 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5129 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5133 /** Handle pending resizing of tracks */
5135 Editor::idle_resize ()
5137 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5139 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5140 selection->tracks.contains (_pending_resize_view)) {
5142 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5143 if (*i != _pending_resize_view) {
5144 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5149 _pending_resize_amount = 0;
5150 _group_tabs->set_dirty ();
5151 resize_idle_id = -1;
5159 ENSURE_GUI_THREAD (*this, &Editor::located);
5162 playhead_cursor->set_position (_session->audible_frame ());
5163 if (_follow_playhead && !_pending_initial_locate) {
5164 reset_x_origin_to_follow_playhead ();
5168 _pending_locate_request = false;
5169 _pending_initial_locate = false;
5173 Editor::region_view_added (RegionView * rv)
5175 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5176 if (rv->region ()->id () == (*pr)) {
5177 selection->add (rv);
5178 selection->regions.pending.erase (pr);
5183 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5185 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5186 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5187 if (rv->region()->id () == (*rnote).first) {
5188 mrv->select_notes ((*rnote).second);
5189 selection->pending_midi_note_selection.erase(rnote);
5195 _summary->set_background_dirty ();
5199 Editor::region_view_removed ()
5201 _summary->set_background_dirty ();
5205 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5207 TrackViewList::const_iterator j = track_views.begin ();
5208 while (j != track_views.end()) {
5209 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5210 if (rtv && rtv->route() == r) {
5221 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5225 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5226 TimeAxisView* tv = axis_view_from_route (*i);
5236 Editor::suspend_route_redisplay ()
5239 _routes->suspend_redisplay();
5244 Editor::resume_route_redisplay ()
5247 _routes->redisplay(); // queue redisplay
5248 _routes->resume_redisplay();
5253 Editor::add_vcas (VCAList& vlist)
5257 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5258 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5261 add_stripables (sl);
5265 Editor::add_routes (RouteList& rlist)
5269 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5273 add_stripables (sl);
5277 Editor::add_stripables (StripableList& sl)
5279 list<TimeAxisView*> new_views;
5280 boost::shared_ptr<VCA> v;
5281 boost::shared_ptr<Route> r;
5282 TrackViewList new_selection;
5283 bool from_scratch = (track_views.size() == 0);
5285 sl.sort (StripablePresentationInfoSorter());
5287 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5289 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5291 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5293 new_views.push_back (vtv);
5295 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5297 if (r->is_auditioner() || r->is_monitor()) {
5301 RouteTimeAxisView* rtv;
5302 DataType dt = r->input()->default_type();
5304 if (dt == ARDOUR::DataType::AUDIO) {
5305 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5307 } else if (dt == ARDOUR::DataType::MIDI) {
5308 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5311 throw unknown_type();
5314 new_views.push_back (rtv);
5315 track_views.push_back (rtv);
5316 new_selection.push_back (rtv);
5318 rtv->effective_gain_display ();
5320 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5321 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5325 if (new_views.size() > 0) {
5326 _routes->time_axis_views_added (new_views);
5327 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5330 /* note: !new_selection.empty() means that we got some routes rather
5334 if (!from_scratch && !new_selection.empty()) {
5335 selection->tracks.clear();
5336 selection->add (new_selection);
5337 begin_selection_op_history();
5340 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5341 show_editor_mixer (true);
5344 editor_list_button.set_sensitive (true);
5348 Editor::timeaxisview_deleted (TimeAxisView *tv)
5350 if (tv == entered_track) {
5354 if (_session && _session->deletion_in_progress()) {
5355 /* the situation is under control */
5359 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5361 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5363 _routes->route_removed (tv);
5365 TimeAxisView::Children c = tv->get_child_list ();
5366 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5367 if (entered_track == i->get()) {
5372 /* remove it from the list of track views */
5374 TrackViewList::iterator i;
5376 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5377 i = track_views.erase (i);
5380 /* update whatever the current mixer strip is displaying, if revelant */
5382 boost::shared_ptr<Route> route;
5385 route = rtav->route ();
5388 if (current_mixer_strip && current_mixer_strip->route() == route) {
5390 TimeAxisView* next_tv;
5392 if (track_views.empty()) {
5394 } else if (i == track_views.end()) {
5395 next_tv = track_views.front();
5402 set_selected_mixer_strip (*next_tv);
5404 /* make the editor mixer strip go away setting the
5405 * button to inactive (which also unticks the menu option)
5408 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5414 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5416 if (apply_to_selection) {
5417 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5419 TrackSelection::iterator j = i;
5422 hide_track_in_display (*i, false);
5427 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5429 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5430 // this will hide the mixer strip
5431 set_selected_mixer_strip (*tv);
5434 _routes->hide_track_in_display (*tv);
5439 Editor::sync_track_view_list_and_routes ()
5441 track_views = TrackViewList (_routes->views ());
5443 _summary->set_background_dirty();
5444 _group_tabs->set_dirty ();
5446 return false; // do not call again (until needed)
5450 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5452 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5457 /** Find a RouteTimeAxisView by the ID of its route */
5459 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5461 RouteTimeAxisView* v;
5463 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5464 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5465 if(v->route()->id() == id) {
5475 Editor::fit_route_group (RouteGroup *g)
5477 TrackViewList ts = axis_views_from_routes (g->route_list ());
5482 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5484 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5487 _session->cancel_audition ();
5491 if (_session->is_auditioning()) {
5492 _session->cancel_audition ();
5493 if (r == last_audition_region) {
5498 _session->audition_region (r);
5499 last_audition_region = r;
5504 Editor::hide_a_region (boost::shared_ptr<Region> r)
5506 r->set_hidden (true);
5510 Editor::show_a_region (boost::shared_ptr<Region> r)
5512 r->set_hidden (false);
5516 Editor::audition_region_from_region_list ()
5518 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5522 Editor::hide_region_from_region_list ()
5524 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5528 Editor::show_region_in_region_list ()
5530 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5534 Editor::step_edit_status_change (bool yn)
5537 start_step_editing ();
5539 stop_step_editing ();
5544 Editor::start_step_editing ()
5546 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5550 Editor::stop_step_editing ()
5552 step_edit_connection.disconnect ();
5556 Editor::check_step_edit ()
5558 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5559 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5561 mtv->check_step_edit ();
5565 return true; // do it again, till we stop
5569 Editor::scroll_press (Direction dir)
5571 ++_scroll_callbacks;
5573 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5574 /* delay the first auto-repeat */
5580 scroll_backward (1);
5588 scroll_up_one_track ();
5592 scroll_down_one_track ();
5596 /* do hacky auto-repeat */
5597 if (!_scroll_connection.connected ()) {
5599 _scroll_connection = Glib::signal_timeout().connect (
5600 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5603 _scroll_callbacks = 0;
5610 Editor::scroll_release ()
5612 _scroll_connection.disconnect ();
5615 /** Queue a change for the Editor viewport x origin to follow the playhead */
5617 Editor::reset_x_origin_to_follow_playhead ()
5619 framepos_t const frame = playhead_cursor->current_frame ();
5621 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5623 if (_session->transport_speed() < 0) {
5625 if (frame > (current_page_samples() / 2)) {
5626 center_screen (frame-(current_page_samples()/2));
5628 center_screen (current_page_samples()/2);
5635 if (frame < leftmost_frame) {
5637 if (_session->transport_rolling()) {
5638 /* rolling; end up with the playhead at the right of the page */
5639 l = frame - current_page_samples ();
5641 /* not rolling: end up with the playhead 1/4 of the way along the page */
5642 l = frame - current_page_samples() / 4;
5646 if (_session->transport_rolling()) {
5647 /* rolling: end up with the playhead on the left of the page */
5650 /* not rolling: end up with the playhead 3/4 of the way along the page */
5651 l = frame - 3 * current_page_samples() / 4;
5659 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5665 Editor::super_rapid_screen_update ()
5667 if (!_session || !_session->engine().running()) {
5671 /* METERING / MIXER STRIPS */
5673 /* update track meters, if required */
5674 if (contents().is_mapped() && meters_running) {
5675 RouteTimeAxisView* rtv;
5676 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5677 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5678 rtv->fast_update ();
5683 /* and any current mixer strip */
5684 if (current_mixer_strip) {
5685 current_mixer_strip->fast_update ();
5688 /* PLAYHEAD AND VIEWPORT */
5690 framepos_t const frame = _session->audible_frame();
5692 /* There are a few reasons why we might not update the playhead / viewport stuff:
5694 * 1. we don't update things when there's a pending locate request, otherwise
5695 * when the editor requests a locate there is a chance that this method
5696 * will move the playhead before the locate request is processed, causing
5698 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5699 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5702 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5704 last_update_frame = frame;
5706 if (!_dragging_playhead) {
5707 playhead_cursor->set_position (frame);
5710 if (!_stationary_playhead) {
5712 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5713 /* We only do this if we aren't already
5714 handling a visual change (ie if
5715 pending_visual_change.being_handled is
5716 false) so that these requests don't stack
5717 up there are too many of them to handle in
5720 reset_x_origin_to_follow_playhead ();
5725 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5726 framepos_t const frame = playhead_cursor->current_frame ();
5727 double target = ((double)frame - (double)current_page_samples()/2.0);
5728 if (target <= 0.0) {
5731 // compare to EditorCursor::set_position()
5732 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5733 double const new_pos = sample_to_pixel_unrounded (target);
5734 if (rint (new_pos) != rint (old_pos)) {
5735 reset_x_origin (pixel_to_sample (floor (new_pos)));
5746 Editor::session_going_away ()
5748 _have_idled = false;
5750 _session_connections.drop_connections ();
5752 super_rapid_screen_update_connection.disconnect ();
5754 selection->clear ();
5755 cut_buffer->clear ();
5757 clicked_regionview = 0;
5758 clicked_axisview = 0;
5759 clicked_routeview = 0;
5760 entered_regionview = 0;
5762 last_update_frame = 0;
5765 playhead_cursor->hide ();
5767 /* rip everything out of the list displays */
5771 _route_groups->clear ();
5773 /* do this first so that deleting a track doesn't reset cms to null
5774 and thus cause a leak.
5777 if (current_mixer_strip) {
5778 if (current_mixer_strip->get_parent() != 0) {
5779 global_hpacker.remove (*current_mixer_strip);
5781 delete current_mixer_strip;
5782 current_mixer_strip = 0;
5785 /* delete all trackviews */
5787 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5790 track_views.clear ();
5792 nudge_clock->set_session (0);
5794 editor_list_button.set_active(false);
5795 editor_list_button.set_sensitive(false);
5797 /* clear tempo/meter rulers */
5798 remove_metric_marks ();
5800 clear_marker_display ();
5802 stop_step_editing ();
5806 /* get rid of any existing editor mixer strip */
5808 WindowTitle title(Glib::get_application_name());
5809 title += _("Editor");
5811 own_window()->set_title (title.get_string());
5814 SessionHandlePtr::session_going_away ();
5818 Editor::trigger_script (int i)
5820 LuaInstance::instance()-> call_action (i);
5824 Editor::set_script_action_name (int i, const std::string& n)
5826 string const a = string_compose (X_("script-action-%1"), i + 1);
5827 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5830 act->set_label (string_compose (_("Unset #%1"), i + 1));
5831 act->set_tooltip (_("no action bound"));
5832 act->set_sensitive (false);
5835 act->set_tooltip (n);
5836 act->set_sensitive (true);
5838 KeyEditor::UpdateBindings ();
5842 Editor::show_editor_list (bool yn)
5845 _the_notebook.show ();
5847 _the_notebook.hide ();
5852 Editor::change_region_layering_order (bool from_context_menu)
5854 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5856 if (!clicked_routeview) {
5857 if (layering_order_editor) {
5858 layering_order_editor->hide ();
5863 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5869 boost::shared_ptr<Playlist> pl = track->playlist();
5875 if (layering_order_editor == 0) {
5876 layering_order_editor = new RegionLayeringOrderEditor (*this);
5879 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5880 layering_order_editor->maybe_present ();
5884 Editor::update_region_layering_order_editor ()
5886 if (layering_order_editor && layering_order_editor->is_visible ()) {
5887 change_region_layering_order (true);
5892 Editor::setup_fade_images ()
5894 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5895 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5896 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5897 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5898 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5900 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5901 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5902 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5903 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5904 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5906 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5907 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5908 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5909 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5910 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5912 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5913 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5914 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5915 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5916 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5920 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5922 Editor::action_menu_item (std::string const & name)
5924 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5927 return *manage (a->create_menu_item ());
5931 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5933 EventBox* b = manage (new EventBox);
5934 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5935 Label* l = manage (new Label (name));
5939 _the_notebook.append_page (widget, *b);
5943 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5945 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5946 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5949 if (ev->type == GDK_2BUTTON_PRESS) {
5951 /* double-click on a notebook tab shrinks or expands the notebook */
5953 if (_notebook_shrunk) {
5954 if (pre_notebook_shrink_pane_width) {
5955 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
5957 _notebook_shrunk = false;
5959 pre_notebook_shrink_pane_width = edit_pane.get_divider();
5961 /* this expands the LHS of the edit pane to cover the notebook
5962 PAGE but leaves the tabs visible.
5964 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
5965 _notebook_shrunk = true;
5973 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5975 using namespace Menu_Helpers;
5977 MenuList& items = _control_point_context_menu.items ();
5980 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5981 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5982 if (!can_remove_control_point (item)) {
5983 items.back().set_sensitive (false);
5986 _control_point_context_menu.popup (event->button.button, event->button.time);
5990 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5992 using namespace Menu_Helpers;
5994 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5999 /* We need to get the selection here and pass it to the operations, since
6000 popping up the menu will cause a region leave event which clears
6001 entered_regionview. */
6003 MidiRegionView& mrv = note->region_view();
6004 const RegionSelection rs = get_regions_from_selection_and_entered ();
6005 const uint32_t sel_size = mrv.selection_size ();
6007 MenuList& items = _note_context_menu.items();
6011 items.push_back(MenuElem(_("Delete"),
6012 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6015 items.push_back(MenuElem(_("Edit..."),
6016 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6017 if (sel_size != 1) {
6018 items.back().set_sensitive (false);
6021 items.push_back(MenuElem(_("Transpose..."),
6022 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6025 items.push_back(MenuElem(_("Legatize"),
6026 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6028 items.back().set_sensitive (false);
6031 items.push_back(MenuElem(_("Quantize..."),
6032 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6034 items.push_back(MenuElem(_("Remove Overlap"),
6035 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6037 items.back().set_sensitive (false);
6040 items.push_back(MenuElem(_("Transform..."),
6041 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6043 _note_context_menu.popup (event->button.button, event->button.time);
6047 Editor::zoom_vertical_modifier_released()
6049 _stepping_axis_view = 0;
6053 Editor::ui_parameter_changed (string parameter)
6055 if (parameter == "icon-set") {
6056 while (!_cursor_stack.empty()) {
6057 _cursor_stack.pop_back();
6059 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6060 _cursor_stack.push_back(_cursors->grabber);
6061 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6062 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6064 } else if (parameter == "draggable-playhead") {
6065 if (_verbose_cursor) {
6066 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6072 Editor::use_own_window (bool and_fill_it)
6074 bool new_window = !own_window();
6076 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6078 if (win && new_window) {
6079 win->set_name ("EditorWindow");
6081 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6083 // win->signal_realize().connect (*this, &Editor::on_realize);
6084 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6085 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6086 win->set_data ("ardour-bindings", bindings);
6091 DisplaySuspender ds;
6092 contents().show_all ();
6094 /* XXX: this is a bit unfortunate; it would probably
6095 be nicer if we could just call show () above rather
6096 than needing the show_all ()
6099 /* re-hide stuff if necessary */
6100 editor_list_button_toggled ();
6101 parameter_changed ("show-summary");
6102 parameter_changed ("show-group-tabs");
6103 parameter_changed ("show-zoom-tools");
6105 /* now reset all audio_time_axis heights, because widgets might need
6111 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6112 tv = (static_cast<TimeAxisView*>(*i));
6113 tv->reset_height ();
6116 if (current_mixer_strip) {
6117 current_mixer_strip->hide_things ();
6118 current_mixer_strip->parameter_changed ("mixer-element-visibility");