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::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
809 ControlProtocol::RemoveStripableFromSelection.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());
811 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
812 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
814 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
818 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
820 /* problematic: has to return a value and thus cannot be x-thread */
822 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
824 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
825 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
827 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
829 _ignore_region_action = false;
830 _last_region_menu_was_main = false;
831 _popup_region_menu_item = 0;
833 _ignore_follow_edits = false;
835 _show_marker_lines = false;
837 /* Button bindings */
839 button_bindings = new Bindings ("editor-mouse");
841 XMLNode* node = button_settings();
843 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
844 button_bindings->load_operation (**i);
850 /* grab current parameter state */
851 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
852 UIConfiguration::instance().map_parameters (pc);
854 setup_fade_images ();
856 LuaInstance::instance(); // instantiate
857 LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &Editor::set_script_action_name));
864 delete button_bindings;
866 delete _route_groups;
867 delete _track_canvas_viewport;
870 delete quantize_dialog;
876 delete _playlist_selector;
878 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
884 Editor::button_settings () const
886 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
887 XMLNode* node = find_named_node (*settings, X_("Buttons"));
890 node = new XMLNode (X_("Buttons"));
897 Editor::get_smart_mode () const
899 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
903 Editor::catch_vanishing_regionview (RegionView *rv)
905 /* note: the selection will take care of the vanishing
906 audioregionview by itself.
909 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
913 if (clicked_regionview == rv) {
914 clicked_regionview = 0;
917 if (entered_regionview == rv) {
918 set_entered_regionview (0);
921 if (!_all_region_actions_sensitized) {
922 sensitize_all_region_actions (true);
927 Editor::set_entered_regionview (RegionView* rv)
929 if (rv == entered_regionview) {
933 if (entered_regionview) {
934 entered_regionview->exited ();
937 entered_regionview = rv;
939 if (entered_regionview != 0) {
940 entered_regionview->entered ();
943 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
944 /* This RegionView entry might have changed what region actions
945 are allowed, so sensitize them all in case a key is pressed.
947 sensitize_all_region_actions (true);
952 Editor::set_entered_track (TimeAxisView* tav)
955 entered_track->exited ();
961 entered_track->entered ();
966 Editor::instant_save ()
968 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
973 _session->add_instant_xml(get_state());
975 Config->add_instant_xml(get_state());
980 Editor::control_vertical_zoom_in_all ()
982 tav_zoom_smooth (false, true);
986 Editor::control_vertical_zoom_out_all ()
988 tav_zoom_smooth (true, true);
992 Editor::control_vertical_zoom_in_selected ()
994 tav_zoom_smooth (false, false);
998 Editor::control_vertical_zoom_out_selected ()
1000 tav_zoom_smooth (true, false);
1004 Editor::control_view (uint32_t view)
1006 goto_visual_state (view);
1010 Editor::control_unselect ()
1012 selection->clear_tracks ();
1016 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1018 TimeAxisView* tav = axis_view_from_stripable (s);
1022 case Selection::Add:
1023 selection->add (tav);
1025 case Selection::Toggle:
1026 selection->toggle (tav);
1028 case Selection::Extend:
1030 case Selection::Set:
1031 selection->set (tav);
1035 selection->clear_tracks ();
1040 Editor::control_step_tracks_up ()
1042 scroll_tracks_up_line ();
1046 Editor::control_step_tracks_down ()
1048 scroll_tracks_down_line ();
1052 Editor::control_scroll (float fraction)
1054 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1060 double step = fraction * current_page_samples();
1063 _control_scroll_target is an optional<T>
1065 it acts like a pointer to an framepos_t, with
1066 a operator conversion to boolean to check
1067 that it has a value could possibly use
1068 playhead_cursor->current_frame to store the
1069 value and a boolean in the class to know
1070 when it's out of date
1073 if (!_control_scroll_target) {
1074 _control_scroll_target = _session->transport_frame();
1075 _dragging_playhead = true;
1078 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1079 *_control_scroll_target = 0;
1080 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1081 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1083 *_control_scroll_target += (framepos_t) trunc (step);
1086 /* move visuals, we'll catch up with it later */
1088 playhead_cursor->set_position (*_control_scroll_target);
1089 UpdateAllTransportClocks (*_control_scroll_target);
1091 if (*_control_scroll_target > (current_page_samples() / 2)) {
1092 /* try to center PH in window */
1093 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1099 Now we do a timeout to actually bring the session to the right place
1100 according to the playhead. This is to avoid reading disk buffers on every
1101 call to control_scroll, which is driven by ScrollTimeline and therefore
1102 probably by a control surface wheel which can generate lots of events.
1104 /* cancel the existing timeout */
1106 control_scroll_connection.disconnect ();
1108 /* add the next timeout */
1110 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1114 Editor::deferred_control_scroll (framepos_t /*target*/)
1116 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1117 // reset for next stream
1118 _control_scroll_target = boost::none;
1119 _dragging_playhead = false;
1124 Editor::access_action (std::string action_group, std::string action_item)
1130 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1133 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1141 Editor::on_realize ()
1145 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1146 start_lock_event_timing ();
1151 Editor::start_lock_event_timing ()
1153 /* check if we should lock the GUI every 30 seconds */
1155 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1159 Editor::generic_event_handler (GdkEvent* ev)
1162 case GDK_BUTTON_PRESS:
1163 case GDK_BUTTON_RELEASE:
1164 case GDK_MOTION_NOTIFY:
1166 case GDK_KEY_RELEASE:
1167 if (contents().is_mapped()) {
1168 gettimeofday (&last_event_time, 0);
1172 case GDK_LEAVE_NOTIFY:
1173 switch (ev->crossing.detail) {
1174 case GDK_NOTIFY_UNKNOWN:
1175 case GDK_NOTIFY_INFERIOR:
1176 case GDK_NOTIFY_ANCESTOR:
1178 case GDK_NOTIFY_VIRTUAL:
1179 case GDK_NOTIFY_NONLINEAR:
1180 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1181 /* leaving window, so reset focus, thus ending any and
1182 all text entry operations.
1184 reset_focus (&contents());
1197 Editor::lock_timeout_callback ()
1199 struct timeval now, delta;
1201 gettimeofday (&now, 0);
1203 timersub (&now, &last_event_time, &delta);
1205 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1207 /* don't call again. Returning false will effectively
1208 disconnect us from the timer callback.
1210 unlock() will call start_lock_event_timing() to get things
1220 Editor::map_position_change (framepos_t frame)
1222 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1224 if (_session == 0) {
1228 if (_follow_playhead) {
1229 center_screen (frame);
1232 playhead_cursor->set_position (frame);
1236 Editor::center_screen (framepos_t frame)
1238 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1240 /* if we're off the page, then scroll.
1243 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1244 center_screen_internal (frame, page);
1249 Editor::center_screen_internal (framepos_t frame, float page)
1254 frame -= (framepos_t) page;
1259 reset_x_origin (frame);
1264 Editor::update_title ()
1266 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1268 if (!own_window()) {
1273 bool dirty = _session->dirty();
1275 string session_name;
1277 if (_session->snap_name() != _session->name()) {
1278 session_name = _session->snap_name();
1280 session_name = _session->name();
1284 session_name = "*" + session_name;
1287 WindowTitle title(session_name);
1288 title += S_("Window|Editor");
1289 title += Glib::get_application_name();
1290 own_window()->set_title (title.get_string());
1292 /* ::session_going_away() will have taken care of it */
1297 Editor::set_session (Session *t)
1299 SessionHandlePtr::set_session (t);
1305 _playlist_selector->set_session (_session);
1306 nudge_clock->set_session (_session);
1307 _summary->set_session (_session);
1308 _group_tabs->set_session (_session);
1309 _route_groups->set_session (_session);
1310 _regions->set_session (_session);
1311 _snapshots->set_session (_session);
1312 _routes->set_session (_session);
1313 _locations->set_session (_session);
1315 if (rhythm_ferret) {
1316 rhythm_ferret->set_session (_session);
1319 if (analysis_window) {
1320 analysis_window->set_session (_session);
1324 sfbrowser->set_session (_session);
1327 compute_fixed_ruler_scale ();
1329 /* Make sure we have auto loop and auto punch ranges */
1331 Location* loc = _session->locations()->auto_loop_location();
1333 loc->set_name (_("Loop"));
1336 loc = _session->locations()->auto_punch_location();
1339 loc->set_name (_("Punch"));
1342 refresh_location_display ();
1344 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1345 the selected Marker; this needs the LocationMarker list to be available.
1347 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1348 set_state (*node, Stateful::loading_state_version);
1350 /* catch up with the playhead */
1352 _session->request_locate (playhead_cursor->current_frame ());
1353 _pending_initial_locate = true;
1357 /* These signals can all be emitted by a non-GUI thread. Therefore the
1358 handlers for them must not attempt to directly interact with the GUI,
1359 but use PBD::Signal<T>::connect() which accepts an event loop
1360 ("context") where the handler will be asked to run.
1363 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1364 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1365 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1366 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1367 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1368 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1369 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1370 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::marker_position_changed, this), gui_context());
1371 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1372 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1373 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1374 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1375 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1376 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1377 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1379 playhead_cursor->show ();
1381 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1382 Config->map_parameters (pc);
1383 _session->config.map_parameters (pc);
1385 restore_ruler_visibility ();
1386 //tempo_map_changed (PropertyChange (0));
1387 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1389 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1390 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1393 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1394 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1397 switch (_snap_type) {
1398 case SnapToRegionStart:
1399 case SnapToRegionEnd:
1400 case SnapToRegionSync:
1401 case SnapToRegionBoundary:
1402 build_region_boundary_cache ();
1409 /* catch up on selection of stripables (other selection state is lost
1410 * when a session is closed
1415 _session->get_stripables (sl);
1416 for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
1417 if ((*s)->presentation_info().selected()) {
1418 RouteTimeAxisView* rtav = get_route_view_by_route_id ((*s)->id());
1420 tl.push_back (rtav);
1425 selection->set (tl);
1428 /* register for undo history */
1429 _session->register_with_memento_command_factory(id(), this);
1430 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1432 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1434 LuaInstance::instance()->set_session(_session);
1436 start_updating_meters ();
1440 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1442 if (a->get_name() == "RegionMenu") {
1443 /* When the main menu's region menu is opened, we setup the actions so that they look right
1444 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1445 so we resensitize all region actions when the entered regionview or the region selection
1446 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1447 happens after the region context menu is opened. So we set a flag here, too.
1451 sensitize_the_right_region_actions ();
1452 _last_region_menu_was_main = true;
1457 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1459 using namespace Menu_Helpers;
1461 void (Editor::*emf)(FadeShape);
1462 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1465 images = &_xfade_in_images;
1466 emf = &Editor::set_fade_in_shape;
1468 images = &_xfade_out_images;
1469 emf = &Editor::set_fade_out_shape;
1474 _("Linear (for highly correlated material)"),
1475 *(*images)[FadeLinear],
1476 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1480 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1484 _("Constant power"),
1485 *(*images)[FadeConstantPower],
1486 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1489 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1494 *(*images)[FadeSymmetric],
1495 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1499 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1504 *(*images)[FadeSlow],
1505 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1508 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1513 *(*images)[FadeFast],
1514 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1517 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1520 /** Pop up a context menu for when the user clicks on a start crossfade */
1522 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1524 using namespace Menu_Helpers;
1525 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1530 MenuList& items (xfade_in_context_menu.items());
1533 if (arv->audio_region()->fade_in_active()) {
1534 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1536 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1539 items.push_back (SeparatorElem());
1540 fill_xfade_menu (items, true);
1542 xfade_in_context_menu.popup (button, time);
1545 /** Pop up a context menu for when the user clicks on an end crossfade */
1547 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1549 using namespace Menu_Helpers;
1550 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1555 MenuList& items (xfade_out_context_menu.items());
1558 if (arv->audio_region()->fade_out_active()) {
1559 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1561 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1564 items.push_back (SeparatorElem());
1565 fill_xfade_menu (items, false);
1567 xfade_out_context_menu.popup (button, time);
1571 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1573 using namespace Menu_Helpers;
1574 Menu* (Editor::*build_menu_function)();
1577 switch (item_type) {
1579 case RegionViewName:
1580 case RegionViewNameHighlight:
1581 case LeftFrameHandle:
1582 case RightFrameHandle:
1583 if (with_selection) {
1584 build_menu_function = &Editor::build_track_selection_context_menu;
1586 build_menu_function = &Editor::build_track_region_context_menu;
1591 if (with_selection) {
1592 build_menu_function = &Editor::build_track_selection_context_menu;
1594 build_menu_function = &Editor::build_track_context_menu;
1599 if (clicked_routeview->track()) {
1600 build_menu_function = &Editor::build_track_context_menu;
1602 build_menu_function = &Editor::build_track_bus_context_menu;
1607 /* probably shouldn't happen but if it does, we don't care */
1611 menu = (this->*build_menu_function)();
1612 menu->set_name ("ArdourContextMenu");
1614 /* now handle specific situations */
1616 switch (item_type) {
1618 case RegionViewName:
1619 case RegionViewNameHighlight:
1620 case LeftFrameHandle:
1621 case RightFrameHandle:
1622 if (!with_selection) {
1623 if (region_edit_menu_split_item) {
1624 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1625 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1627 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1630 if (region_edit_menu_split_multichannel_item) {
1631 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1632 region_edit_menu_split_multichannel_item->set_sensitive (true);
1634 region_edit_menu_split_multichannel_item->set_sensitive (false);
1647 /* probably shouldn't happen but if it does, we don't care */
1651 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1653 /* Bounce to disk */
1655 using namespace Menu_Helpers;
1656 MenuList& edit_items = menu->items();
1658 edit_items.push_back (SeparatorElem());
1660 switch (clicked_routeview->audio_track()->freeze_state()) {
1661 case AudioTrack::NoFreeze:
1662 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1665 case AudioTrack::Frozen:
1666 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1669 case AudioTrack::UnFrozen:
1670 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1676 if (item_type == StreamItem && clicked_routeview) {
1677 clicked_routeview->build_underlay_menu(menu);
1680 /* When the region menu is opened, we setup the actions so that they look right
1683 sensitize_the_right_region_actions ();
1684 _last_region_menu_was_main = false;
1686 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1687 menu->popup (button, time);
1691 Editor::build_track_context_menu ()
1693 using namespace Menu_Helpers;
1695 MenuList& edit_items = track_context_menu.items();
1698 add_dstream_context_items (edit_items);
1699 return &track_context_menu;
1703 Editor::build_track_bus_context_menu ()
1705 using namespace Menu_Helpers;
1707 MenuList& edit_items = track_context_menu.items();
1710 add_bus_context_items (edit_items);
1711 return &track_context_menu;
1715 Editor::build_track_region_context_menu ()
1717 using namespace Menu_Helpers;
1718 MenuList& edit_items = track_region_context_menu.items();
1721 /* we've just cleared the track region context menu, so the menu that these
1722 two items were on will have disappeared; stop them dangling.
1724 region_edit_menu_split_item = 0;
1725 region_edit_menu_split_multichannel_item = 0;
1727 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1730 boost::shared_ptr<Track> tr;
1731 boost::shared_ptr<Playlist> pl;
1733 if ((tr = rtv->track())) {
1734 add_region_context_items (edit_items, tr);
1738 add_dstream_context_items (edit_items);
1740 return &track_region_context_menu;
1744 Editor::loudness_analyze_region_selection ()
1749 Selection& s (PublicEditor::instance ().get_selection ());
1750 RegionSelection ars = s.regions;
1751 ARDOUR::AnalysisGraph ag (_session);
1752 framecnt_t total_work = 0;
1754 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1755 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1759 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1762 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1763 total_work += arv->region ()->length ();
1766 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1768 ag.set_total_frames (total_work);
1769 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1772 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1773 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1777 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1781 ag.analyze_region (ar);
1784 if (!ag.canceled ()) {
1785 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1791 Editor::loudness_analyze_range_selection ()
1796 Selection& s (PublicEditor::instance ().get_selection ());
1797 TimeSelection ts = s.time;
1798 ARDOUR::AnalysisGraph ag (_session);
1799 framecnt_t total_work = 0;
1801 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1802 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1806 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1810 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1811 total_work += j->length ();
1815 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1817 ag.set_total_frames (total_work);
1818 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1821 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1822 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1826 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1830 ag.analyze_range (rui->route (), pl, ts);
1833 if (!ag.canceled ()) {
1834 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1840 Editor::spectral_analyze_region_selection ()
1842 if (analysis_window == 0) {
1843 analysis_window = new AnalysisWindow();
1846 analysis_window->set_session(_session);
1848 analysis_window->show_all();
1851 analysis_window->set_regionmode();
1852 analysis_window->analyze();
1854 analysis_window->present();
1858 Editor::spectral_analyze_range_selection()
1860 if (analysis_window == 0) {
1861 analysis_window = new AnalysisWindow();
1864 analysis_window->set_session(_session);
1866 analysis_window->show_all();
1869 analysis_window->set_rangemode();
1870 analysis_window->analyze();
1872 analysis_window->present();
1876 Editor::build_track_selection_context_menu ()
1878 using namespace Menu_Helpers;
1879 MenuList& edit_items = track_selection_context_menu.items();
1880 edit_items.clear ();
1882 add_selection_context_items (edit_items);
1883 // edit_items.push_back (SeparatorElem());
1884 // add_dstream_context_items (edit_items);
1886 return &track_selection_context_menu;
1890 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1892 using namespace Menu_Helpers;
1894 /* OK, stick the region submenu at the top of the list, and then add
1898 RegionSelection rs = get_regions_from_selection_and_entered ();
1900 string::size_type pos = 0;
1901 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1903 /* we have to hack up the region name because "_" has a special
1904 meaning for menu titles.
1907 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1908 menu_item_name.replace (pos, 1, "__");
1912 if (_popup_region_menu_item == 0) {
1913 _popup_region_menu_item = new MenuItem (menu_item_name);
1914 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1915 _popup_region_menu_item->show ();
1917 _popup_region_menu_item->set_label (menu_item_name);
1920 /* No latering allowed in later is higher layering model */
1921 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1922 if (act && Config->get_layer_model() == LaterHigher) {
1923 act->set_sensitive (false);
1925 act->set_sensitive (true);
1928 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1930 edit_items.push_back (*_popup_region_menu_item);
1931 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1932 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1934 edit_items.push_back (SeparatorElem());
1937 /** Add context menu items relevant to selection ranges.
1938 * @param edit_items List to add the items to.
1941 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1943 using namespace Menu_Helpers;
1945 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1946 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1948 edit_items.push_back (SeparatorElem());
1949 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1951 edit_items.push_back (SeparatorElem());
1952 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1953 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1955 edit_items.push_back (SeparatorElem());
1957 edit_items.push_back (
1959 _("Move Range Start to Previous Region Boundary"),
1960 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1964 edit_items.push_back (
1966 _("Move Range Start to Next Region Boundary"),
1967 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1971 edit_items.push_back (
1973 _("Move Range End to Previous Region Boundary"),
1974 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1978 edit_items.push_back (
1980 _("Move Range End to Next Region Boundary"),
1981 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1985 edit_items.push_back (SeparatorElem());
1986 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1987 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1989 edit_items.push_back (SeparatorElem());
1990 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1992 edit_items.push_back (SeparatorElem());
1993 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1994 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1995 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1997 edit_items.push_back (SeparatorElem());
1998 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
2000 edit_items.push_back (SeparatorElem());
2001 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
2002 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
2004 edit_items.push_back (SeparatorElem());
2005 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
2006 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
2007 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
2008 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
2009 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
2010 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
2011 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2017 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2019 using namespace Menu_Helpers;
2023 Menu *play_menu = manage (new Menu);
2024 MenuList& play_items = play_menu->items();
2025 play_menu->set_name ("ArdourContextMenu");
2027 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2028 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2029 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2030 play_items.push_back (SeparatorElem());
2031 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2033 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2037 Menu *select_menu = manage (new Menu);
2038 MenuList& select_items = select_menu->items();
2039 select_menu->set_name ("ArdourContextMenu");
2041 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2042 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2043 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2044 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2045 select_items.push_back (SeparatorElem());
2046 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2047 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2048 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2049 select_items.push_back (SeparatorElem());
2050 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2051 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2052 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2053 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2054 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2055 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2056 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2058 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2062 Menu *cutnpaste_menu = manage (new Menu);
2063 MenuList& cutnpaste_items = cutnpaste_menu->items();
2064 cutnpaste_menu->set_name ("ArdourContextMenu");
2066 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2067 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2068 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2070 cutnpaste_items.push_back (SeparatorElem());
2072 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2073 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2075 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2077 /* Adding new material */
2079 edit_items.push_back (SeparatorElem());
2080 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2081 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2085 Menu *nudge_menu = manage (new Menu());
2086 MenuList& nudge_items = nudge_menu->items();
2087 nudge_menu->set_name ("ArdourContextMenu");
2089 edit_items.push_back (SeparatorElem());
2090 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2091 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2092 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2093 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2095 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2099 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2101 using namespace Menu_Helpers;
2105 Menu *play_menu = manage (new Menu);
2106 MenuList& play_items = play_menu->items();
2107 play_menu->set_name ("ArdourContextMenu");
2109 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2110 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2111 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2115 Menu *select_menu = manage (new Menu);
2116 MenuList& select_items = select_menu->items();
2117 select_menu->set_name ("ArdourContextMenu");
2119 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2120 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2121 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2122 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2123 select_items.push_back (SeparatorElem());
2124 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2125 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2126 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2127 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2129 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2133 Menu *cutnpaste_menu = manage (new Menu);
2134 MenuList& cutnpaste_items = cutnpaste_menu->items();
2135 cutnpaste_menu->set_name ("ArdourContextMenu");
2137 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2138 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2139 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2141 Menu *nudge_menu = manage (new Menu());
2142 MenuList& nudge_items = nudge_menu->items();
2143 nudge_menu->set_name ("ArdourContextMenu");
2145 edit_items.push_back (SeparatorElem());
2146 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2147 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2148 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2149 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2151 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2155 Editor::snap_type() const
2161 Editor::snap_musical() const
2163 switch (_snap_type) {
2164 case SnapToBeatDiv128:
2165 case SnapToBeatDiv64:
2166 case SnapToBeatDiv32:
2167 case SnapToBeatDiv28:
2168 case SnapToBeatDiv24:
2169 case SnapToBeatDiv20:
2170 case SnapToBeatDiv16:
2171 case SnapToBeatDiv14:
2172 case SnapToBeatDiv12:
2173 case SnapToBeatDiv10:
2174 case SnapToBeatDiv8:
2175 case SnapToBeatDiv7:
2176 case SnapToBeatDiv6:
2177 case SnapToBeatDiv5:
2178 case SnapToBeatDiv4:
2179 case SnapToBeatDiv3:
2180 case SnapToBeatDiv2:
2192 Editor::snap_mode() const
2198 Editor::set_snap_to (SnapType st)
2200 unsigned int snap_ind = (unsigned int)st;
2202 if (internal_editing()) {
2203 internal_snap_type = st;
2205 pre_internal_snap_type = st;
2210 if (snap_ind > snap_type_strings.size() - 1) {
2212 _snap_type = (SnapType)snap_ind;
2215 string str = snap_type_strings[snap_ind];
2217 if (str != snap_type_selector.get_text()) {
2218 snap_type_selector.set_text (str);
2223 switch (_snap_type) {
2224 case SnapToBeatDiv128:
2225 case SnapToBeatDiv64:
2226 case SnapToBeatDiv32:
2227 case SnapToBeatDiv28:
2228 case SnapToBeatDiv24:
2229 case SnapToBeatDiv20:
2230 case SnapToBeatDiv16:
2231 case SnapToBeatDiv14:
2232 case SnapToBeatDiv12:
2233 case SnapToBeatDiv10:
2234 case SnapToBeatDiv8:
2235 case SnapToBeatDiv7:
2236 case SnapToBeatDiv6:
2237 case SnapToBeatDiv5:
2238 case SnapToBeatDiv4:
2239 case SnapToBeatDiv3:
2240 case SnapToBeatDiv2: {
2241 std::vector<TempoMap::BBTPoint> grid;
2242 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
2243 compute_bbt_ruler_scale (grid, leftmost_frame, leftmost_frame + current_page_samples());
2244 update_tempo_based_rulers (grid);
2248 case SnapToRegionStart:
2249 case SnapToRegionEnd:
2250 case SnapToRegionSync:
2251 case SnapToRegionBoundary:
2252 build_region_boundary_cache ();
2260 redisplay_tempo (false);
2262 SnapChanged (); /* EMIT SIGNAL */
2266 Editor::set_snap_mode (SnapMode mode)
2268 string str = snap_mode_strings[(int)mode];
2270 if (internal_editing()) {
2271 internal_snap_mode = mode;
2273 pre_internal_snap_mode = mode;
2278 if (str != snap_mode_selector.get_text ()) {
2279 snap_mode_selector.set_text (str);
2286 Editor::set_edit_point_preference (EditPoint ep, bool force)
2288 bool changed = (_edit_point != ep);
2291 if (Profile->get_mixbus())
2292 if (ep == EditAtSelectedMarker)
2293 ep = EditAtPlayhead;
2295 string str = edit_point_strings[(int)ep];
2296 if (str != edit_point_selector.get_text ()) {
2297 edit_point_selector.set_text (str);
2300 update_all_enter_cursors();
2302 if (!force && !changed) {
2306 const char* action=NULL;
2308 switch (_edit_point) {
2309 case EditAtPlayhead:
2310 action = "edit-at-playhead";
2312 case EditAtSelectedMarker:
2313 action = "edit-at-marker";
2316 action = "edit-at-mouse";
2320 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2322 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2326 bool in_track_canvas;
2328 if (!mouse_frame (foo, in_track_canvas)) {
2329 in_track_canvas = false;
2332 reset_canvas_action_sensitivity (in_track_canvas);
2338 Editor::set_state (const XMLNode& node, int version)
2340 XMLProperty const * prop;
2342 PBD::Unwinder<bool> nsi (no_save_instant, true);
2345 Tabbable::set_state (node, version);
2347 if (_session && (prop = node.property ("playhead"))) {
2349 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2351 playhead_cursor->set_position (pos);
2353 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2354 playhead_cursor->set_position (0);
2357 playhead_cursor->set_position (0);
2360 if ((prop = node.property ("mixer-width"))) {
2361 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2364 if ((prop = node.property ("zoom-focus"))) {
2365 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2367 zoom_focus_selection_done (zoom_focus);
2370 if ((prop = node.property ("zoom"))) {
2371 /* older versions of ardour used floating point samples_per_pixel */
2372 double f = PBD::atof (prop->value());
2373 reset_zoom (llrintf (f));
2375 reset_zoom (samples_per_pixel);
2378 if ((prop = node.property ("visible-track-count"))) {
2379 set_visible_track_count (PBD::atoi (prop->value()));
2382 if ((prop = node.property ("snap-to"))) {
2383 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2384 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2386 set_snap_to (_snap_type);
2389 if ((prop = node.property ("snap-mode"))) {
2390 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2391 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2392 * snap_mode_selection_done() will only mark an already active item as active
2393 * which does not trigger set_text().
2395 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2397 set_snap_mode (_snap_mode);
2400 if ((prop = node.property ("internal-snap-to"))) {
2401 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2404 if ((prop = node.property ("internal-snap-mode"))) {
2405 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2408 if ((prop = node.property ("pre-internal-snap-to"))) {
2409 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2412 if ((prop = node.property ("pre-internal-snap-mode"))) {
2413 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2416 if ((prop = node.property ("mouse-mode"))) {
2417 MouseMode m = str2mousemode(prop->value());
2418 set_mouse_mode (m, true);
2420 set_mouse_mode (MouseObject, true);
2423 if ((prop = node.property ("left-frame")) != 0) {
2425 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2429 reset_x_origin (pos);
2433 if ((prop = node.property ("y-origin")) != 0) {
2434 reset_y_origin (atof (prop->value ()));
2437 if ((prop = node.property ("join-object-range"))) {
2438 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2439 bool yn = string_is_affirmative (prop->value());
2441 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2442 tact->set_active (!yn);
2443 tact->set_active (yn);
2445 set_mouse_mode(mouse_mode, true);
2448 if ((prop = node.property ("edit-point"))) {
2449 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2451 set_edit_point_preference (_edit_point);
2454 if ((prop = node.property ("show-measures"))) {
2455 bool yn = string_is_affirmative (prop->value());
2456 _show_measures = yn;
2459 if ((prop = node.property ("follow-playhead"))) {
2460 bool yn = string_is_affirmative (prop->value());
2461 set_follow_playhead (yn);
2464 if ((prop = node.property ("stationary-playhead"))) {
2465 bool yn = string_is_affirmative (prop->value());
2466 set_stationary_playhead (yn);
2469 if ((prop = node.property ("region-list-sort-type"))) {
2470 RegionListSortType st;
2471 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2474 if ((prop = node.property ("show-editor-mixer"))) {
2476 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2479 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2480 bool yn = string_is_affirmative (prop->value());
2482 /* do it twice to force the change */
2484 tact->set_active (!yn);
2485 tact->set_active (yn);
2488 if ((prop = node.property ("show-editor-list"))) {
2490 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2493 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2494 bool yn = string_is_affirmative (prop->value());
2496 /* do it twice to force the change */
2498 tact->set_active (!yn);
2499 tact->set_active (yn);
2502 if ((prop = node.property (X_("editor-list-page")))) {
2503 _the_notebook.set_current_page (atoi (prop->value ()));
2506 if ((prop = node.property (X_("show-marker-lines")))) {
2507 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2509 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2510 bool yn = string_is_affirmative (prop->value ());
2512 tact->set_active (!yn);
2513 tact->set_active (yn);
2516 XMLNodeList children = node.children ();
2517 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2518 selection->set_state (**i, Stateful::current_state_version);
2519 _regions->set_state (**i);
2522 if ((prop = node.property ("maximised"))) {
2523 bool yn = string_is_affirmative (prop->value());
2524 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2526 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2527 bool fs = tact && tact->get_active();
2529 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2533 if ((prop = node.property ("nudge-clock-value"))) {
2535 sscanf (prop->value().c_str(), "%" PRId64, &f);
2536 nudge_clock->set (f);
2538 nudge_clock->set_mode (AudioClock::Timecode);
2539 nudge_clock->set (_session->frame_rate() * 5, true);
2544 * Not all properties may have been in XML, but
2545 * those that are linked to a private variable may need changing
2550 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2552 yn = _show_measures;
2553 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2554 /* do it twice to force the change */
2555 tact->set_active (!yn);
2556 tact->set_active (yn);
2559 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2560 yn = _follow_playhead;
2562 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2563 if (tact->get_active() != yn) {
2564 tact->set_active (yn);
2568 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2569 yn = _stationary_playhead;
2571 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2572 if (tact->get_active() != yn) {
2573 tact->set_active (yn);
2578 return LuaInstance::instance()->set_state(node);
2582 Editor::get_state ()
2584 XMLNode* node = new XMLNode (X_("Editor"));
2588 id().print (buf, sizeof (buf));
2589 node->add_property ("id", buf);
2591 node->add_child_nocopy (Tabbable::get_state());
2593 snprintf(buf,sizeof(buf), "%f", edit_pane.get_divider ());
2594 node->add_property("edit-horizontal-pane-pos", string(buf));
2595 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2596 snprintf(buf,sizeof(buf), "%f", editor_summary_pane.get_divider());
2597 node->add_property("edit-vertical-pane-pos", string(buf));
2599 maybe_add_mixer_strip_width (*node);
2601 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2603 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2604 node->add_property ("zoom", buf);
2605 node->add_property ("snap-to", enum_2_string (_snap_type));
2606 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2607 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2608 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2609 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2610 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2611 node->add_property ("edit-point", enum_2_string (_edit_point));
2612 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2613 node->add_property ("visible-track-count", buf);
2615 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2616 node->add_property ("playhead", buf);
2617 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2618 node->add_property ("left-frame", buf);
2619 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2620 node->add_property ("y-origin", buf);
2622 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2623 node->add_property ("maximised", _maximised ? "yes" : "no");
2624 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2625 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2626 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2627 node->add_property ("mouse-mode", enum2str(mouse_mode));
2628 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2630 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2632 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2633 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2636 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2638 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2639 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2642 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2643 node->add_property (X_("editor-list-page"), buf);
2645 if (button_bindings) {
2646 XMLNode* bb = new XMLNode (X_("Buttons"));
2647 button_bindings->save (*bb);
2648 node->add_child_nocopy (*bb);
2651 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2653 node->add_child_nocopy (selection->get_state ());
2654 node->add_child_nocopy (_regions->get_state ());
2656 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2657 node->add_property ("nudge-clock-value", buf);
2659 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2660 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2665 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2666 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2668 * @return pair: TimeAxisView that y is over, layer index.
2670 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2671 * in stacked or expanded region display mode, otherwise 0.
2673 std::pair<TimeAxisView *, double>
2674 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2676 if (!trackview_relative_offset) {
2677 y -= _trackview_group->canvas_origin().y;
2681 return std::make_pair ( (TimeAxisView *) 0, 0);
2684 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2686 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2693 return std::make_pair ( (TimeAxisView *) 0, 0);
2696 /** Snap a position to the grid, if appropriate, taking into account current
2697 * grid settings and also the state of any snap modifier keys that may be pressed.
2698 * @param start Position to snap.
2699 * @param event Event to get current key modifier information from, or 0.
2702 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2704 if (!_session || !event) {
2708 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2709 if (_snap_mode == SnapOff) {
2710 snap_to_internal (start, direction, for_mark);
2713 if (_snap_mode != SnapOff) {
2714 snap_to_internal (start, direction, for_mark);
2715 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2716 /* SnapOff, but we pressed the snap_delta modifier */
2717 snap_to_internal (start, direction, for_mark);
2723 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2725 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2729 snap_to_internal (start, direction, for_mark, ensure_snap);
2733 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2735 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2736 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2738 switch (_snap_type) {
2739 case SnapToTimecodeFrame:
2740 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2741 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2742 /* start is already on a whole timecode frame, do nothing */
2743 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2744 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2746 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2750 case SnapToTimecodeSeconds:
2751 if (_session->config.get_timecode_offset_negative()) {
2752 start += _session->config.get_timecode_offset ();
2754 start -= _session->config.get_timecode_offset ();
2756 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2757 (start % one_timecode_second == 0)) {
2758 /* start is already on a whole second, do nothing */
2759 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2760 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2762 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2765 if (_session->config.get_timecode_offset_negative()) {
2766 start -= _session->config.get_timecode_offset ();
2768 start += _session->config.get_timecode_offset ();
2772 case SnapToTimecodeMinutes:
2773 if (_session->config.get_timecode_offset_negative()) {
2774 start += _session->config.get_timecode_offset ();
2776 start -= _session->config.get_timecode_offset ();
2778 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2779 (start % one_timecode_minute == 0)) {
2780 /* start is already on a whole minute, do nothing */
2781 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2782 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2784 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2786 if (_session->config.get_timecode_offset_negative()) {
2787 start -= _session->config.get_timecode_offset ();
2789 start += _session->config.get_timecode_offset ();
2793 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2794 abort(); /*NOTREACHED*/
2799 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2801 const framepos_t one_second = _session->frame_rate();
2802 const framepos_t one_minute = _session->frame_rate() * 60;
2803 framepos_t presnap = start;
2807 switch (_snap_type) {
2808 case SnapToTimecodeFrame:
2809 case SnapToTimecodeSeconds:
2810 case SnapToTimecodeMinutes:
2811 return timecode_snap_to_internal (start, direction, for_mark);
2814 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2815 start % (one_second/75) == 0) {
2816 /* start is already on a whole CD frame, do nothing */
2817 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2818 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2820 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2825 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2826 start % one_second == 0) {
2827 /* start is already on a whole second, do nothing */
2828 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2829 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2831 start = (framepos_t) floor ((double) start / one_second) * one_second;
2836 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2837 start % one_minute == 0) {
2838 /* start is already on a whole minute, do nothing */
2839 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2840 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2842 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2847 start = _session->tempo_map().round_to_bar (start, direction);
2851 start = _session->tempo_map().round_to_beat (start, direction);
2854 case SnapToBeatDiv128:
2855 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2857 case SnapToBeatDiv64:
2858 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2860 case SnapToBeatDiv32:
2861 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2863 case SnapToBeatDiv28:
2864 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2866 case SnapToBeatDiv24:
2867 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2869 case SnapToBeatDiv20:
2870 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2872 case SnapToBeatDiv16:
2873 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2875 case SnapToBeatDiv14:
2876 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2878 case SnapToBeatDiv12:
2879 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2881 case SnapToBeatDiv10:
2882 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2884 case SnapToBeatDiv8:
2885 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2887 case SnapToBeatDiv7:
2888 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2890 case SnapToBeatDiv6:
2891 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2893 case SnapToBeatDiv5:
2894 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2896 case SnapToBeatDiv4:
2897 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2899 case SnapToBeatDiv3:
2900 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2902 case SnapToBeatDiv2:
2903 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2911 _session->locations()->marks_either_side (start, before, after);
2913 if (before == max_framepos && after == max_framepos) {
2914 /* No marks to snap to, so just don't snap */
2916 } else if (before == max_framepos) {
2918 } else if (after == max_framepos) {
2920 } else if (before != max_framepos && after != max_framepos) {
2921 /* have before and after */
2922 if ((start - before) < (after - start)) {
2931 case SnapToRegionStart:
2932 case SnapToRegionEnd:
2933 case SnapToRegionSync:
2934 case SnapToRegionBoundary:
2935 if (!region_boundary_cache.empty()) {
2937 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2938 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2940 if (direction > 0) {
2941 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2943 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2946 if (next != region_boundary_cache.begin ()) {
2951 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2952 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2954 if (start > (p + n) / 2) {
2963 switch (_snap_mode) {
2973 if (presnap > start) {
2974 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2978 } else if (presnap < start) {
2979 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2985 /* handled at entry */
2993 Editor::setup_toolbar ()
2995 HBox* mode_box = manage(new HBox);
2996 mode_box->set_border_width (2);
2997 mode_box->set_spacing(2);
2999 HBox* mouse_mode_box = manage (new HBox);
3000 HBox* mouse_mode_hbox = manage (new HBox);
3001 VBox* mouse_mode_vbox = manage (new VBox);
3002 Alignment* mouse_mode_align = manage (new Alignment);
3004 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3005 mouse_mode_size_group->add_widget (smart_mode_button);
3006 mouse_mode_size_group->add_widget (mouse_move_button);
3007 mouse_mode_size_group->add_widget (mouse_cut_button);
3008 mouse_mode_size_group->add_widget (mouse_select_button);
3009 mouse_mode_size_group->add_widget (mouse_timefx_button);
3010 mouse_mode_size_group->add_widget (mouse_audition_button);
3011 mouse_mode_size_group->add_widget (mouse_draw_button);
3012 mouse_mode_size_group->add_widget (mouse_content_button);
3014 mouse_mode_size_group->add_widget (zoom_in_button);
3015 mouse_mode_size_group->add_widget (zoom_out_button);
3016 mouse_mode_size_group->add_widget (zoom_preset_selector);
3017 mouse_mode_size_group->add_widget (zoom_out_full_button);
3018 mouse_mode_size_group->add_widget (zoom_focus_selector);
3020 mouse_mode_size_group->add_widget (tav_shrink_button);
3021 mouse_mode_size_group->add_widget (tav_expand_button);
3022 mouse_mode_size_group->add_widget (visible_tracks_selector);
3024 mouse_mode_size_group->add_widget (snap_type_selector);
3025 mouse_mode_size_group->add_widget (snap_mode_selector);
3027 mouse_mode_size_group->add_widget (edit_point_selector);
3028 mouse_mode_size_group->add_widget (edit_mode_selector);
3030 mouse_mode_size_group->add_widget (*nudge_clock);
3031 mouse_mode_size_group->add_widget (nudge_forward_button);
3032 mouse_mode_size_group->add_widget (nudge_backward_button);
3034 mouse_mode_hbox->set_spacing (2);
3036 if (!ARDOUR::Profile->get_trx()) {
3037 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3040 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3041 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3043 if (!ARDOUR::Profile->get_mixbus()) {
3044 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3047 if (!ARDOUR::Profile->get_trx()) {
3048 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3049 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3050 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3051 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3054 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3056 mouse_mode_align->add (*mouse_mode_vbox);
3057 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3059 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3061 edit_mode_selector.set_name ("mouse mode button");
3063 if (!ARDOUR::Profile->get_trx()) {
3064 mode_box->pack_start (edit_mode_selector, false, false);
3067 mode_box->pack_start (*mouse_mode_box, false, false);
3071 _zoom_box.set_spacing (2);
3072 _zoom_box.set_border_width (2);
3076 zoom_preset_selector.set_name ("zoom button");
3077 zoom_preset_selector.set_image(::get_icon ("time_exp"));
3078 zoom_preset_selector.set_size_request (42, -1);
3080 zoom_in_button.set_name ("zoom button");
3081 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3082 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3083 zoom_in_button.set_related_action (act);
3085 zoom_out_button.set_name ("zoom button");
3086 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3087 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3088 zoom_out_button.set_related_action (act);
3090 zoom_out_full_button.set_name ("zoom button");
3091 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3092 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3093 zoom_out_full_button.set_related_action (act);
3095 zoom_focus_selector.set_name ("zoom button");
3097 if (ARDOUR::Profile->get_mixbus()) {
3098 _zoom_box.pack_start (zoom_preset_selector, false, false);
3099 } else if (ARDOUR::Profile->get_trx()) {
3100 mode_box->pack_start (zoom_out_button, false, false);
3101 mode_box->pack_start (zoom_in_button, false, false);
3103 _zoom_box.pack_start (zoom_out_button, false, false);
3104 _zoom_box.pack_start (zoom_in_button, false, false);
3105 _zoom_box.pack_start (zoom_out_full_button, false, false);
3106 _zoom_box.pack_start (zoom_focus_selector, false, false);
3109 /* Track zoom buttons */
3110 visible_tracks_selector.set_name ("zoom button");
3111 if (Profile->get_mixbus()) {
3112 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3113 visible_tracks_selector.set_size_request (42, -1);
3115 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3118 tav_expand_button.set_name ("zoom button");
3119 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3120 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3121 tav_expand_button.set_related_action (act);
3123 tav_shrink_button.set_name ("zoom button");
3124 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3125 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3126 tav_shrink_button.set_related_action (act);
3128 if (ARDOUR::Profile->get_mixbus()) {
3129 _zoom_box.pack_start (visible_tracks_selector);
3130 } else if (ARDOUR::Profile->get_trx()) {
3131 _zoom_box.pack_start (tav_shrink_button);
3132 _zoom_box.pack_start (tav_expand_button);
3134 _zoom_box.pack_start (visible_tracks_selector);
3135 _zoom_box.pack_start (tav_shrink_button);
3136 _zoom_box.pack_start (tav_expand_button);
3139 snap_box.set_spacing (2);
3140 snap_box.set_border_width (2);
3142 snap_type_selector.set_name ("mouse mode button");
3144 snap_mode_selector.set_name ("mouse mode button");
3146 edit_point_selector.set_name ("mouse mode button");
3148 snap_box.pack_start (snap_mode_selector, false, false);
3149 snap_box.pack_start (snap_type_selector, false, false);
3150 snap_box.pack_start (edit_point_selector, false, false);
3154 HBox *nudge_box = manage (new HBox);
3155 nudge_box->set_spacing (2);
3156 nudge_box->set_border_width (2);
3158 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3159 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3161 nudge_box->pack_start (nudge_backward_button, false, false);
3162 nudge_box->pack_start (nudge_forward_button, false, false);
3163 nudge_box->pack_start (*nudge_clock, false, false);
3166 /* Pack everything in... */
3168 HBox* hbox = manage (new HBox);
3169 hbox->set_spacing(2);
3171 toolbar_hbox.set_spacing (2);
3172 toolbar_hbox.set_border_width (1);
3174 toolbar_hbox.pack_start (*mode_box, false, false);
3175 if (!ARDOUR::Profile->get_trx()) {
3176 toolbar_hbox.pack_start (_zoom_box, false, false);
3177 toolbar_hbox.pack_start (*hbox, false, false);
3180 if (!ARDOUR::Profile->get_trx()) {
3181 hbox->pack_start (snap_box, false, false);
3182 hbox->pack_start (*nudge_box, false, false);
3187 toolbar_base.set_name ("ToolBarBase");
3188 toolbar_base.add (toolbar_hbox);
3190 _toolbar_viewport.add (toolbar_base);
3191 /* stick to the required height but allow width to vary if there's not enough room */
3192 _toolbar_viewport.set_size_request (1, -1);
3194 toolbar_frame.set_shadow_type (SHADOW_OUT);
3195 toolbar_frame.set_name ("BaseFrame");
3196 toolbar_frame.add (_toolbar_viewport);
3200 Editor::build_edit_point_menu ()
3202 using namespace Menu_Helpers;
3204 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3205 if(!Profile->get_mixbus())
3206 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3207 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3209 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3213 Editor::build_edit_mode_menu ()
3215 using namespace Menu_Helpers;
3217 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3218 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3219 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3220 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3222 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3226 Editor::build_snap_mode_menu ()
3228 using namespace Menu_Helpers;
3230 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3231 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3232 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3234 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3238 Editor::build_snap_type_menu ()
3240 using namespace Menu_Helpers;
3242 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3243 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3244 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3245 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3246 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3247 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3248 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3249 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3250 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3251 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3252 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3253 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3254 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3255 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3256 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3257 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3258 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3259 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3260 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3261 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3262 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3263 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3264 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3265 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3266 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3267 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3268 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3269 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3270 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3271 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3273 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3278 Editor::setup_tooltips ()
3280 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3281 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3282 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3283 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3284 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3285 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3286 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3287 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3288 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3289 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3290 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3291 set_tooltip (zoom_in_button, _("Zoom In"));
3292 set_tooltip (zoom_out_button, _("Zoom Out"));
3293 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3294 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3295 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3296 set_tooltip (tav_expand_button, _("Expand Tracks"));
3297 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3298 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3299 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3300 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3301 set_tooltip (edit_point_selector, _("Edit Point"));
3302 set_tooltip (edit_mode_selector, _("Edit Mode"));
3303 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3307 Editor::convert_drop_to_paths (
3308 vector<string>& paths,
3309 const RefPtr<Gdk::DragContext>& /*context*/,
3312 const SelectionData& data,
3316 if (_session == 0) {
3320 vector<string> uris = data.get_uris();
3324 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3325 are actually URI lists. So do it by hand.
3328 if (data.get_target() != "text/plain") {
3332 /* Parse the "uri-list" format that Nautilus provides,
3333 where each pathname is delimited by \r\n.
3335 THERE MAY BE NO NULL TERMINATING CHAR!!!
3338 string txt = data.get_text();
3342 p = (char *) malloc (txt.length() + 1);
3343 txt.copy (p, txt.length(), 0);
3344 p[txt.length()] = '\0';
3350 while (g_ascii_isspace (*p))
3354 while (*q && (*q != '\n') && (*q != '\r')) {
3361 while (q > p && g_ascii_isspace (*q))
3366 uris.push_back (string (p, q - p + 1));
3370 p = strchr (p, '\n');
3382 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3383 if ((*i).substr (0,7) == "file://") {
3384 paths.push_back (Glib::filename_from_uri (*i));
3392 Editor::new_tempo_section ()
3397 Editor::map_transport_state ()
3399 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3401 if (_session && _session->transport_stopped()) {
3402 have_pending_keyboard_selection = false;
3405 update_loop_range_view ();
3411 Editor::begin_selection_op_history ()
3413 selection_op_cmd_depth = 0;
3414 selection_op_history_it = 0;
3416 while(!selection_op_history.empty()) {
3417 delete selection_op_history.front();
3418 selection_op_history.pop_front();
3421 selection_undo_action->set_sensitive (false);
3422 selection_redo_action->set_sensitive (false);
3423 selection_op_history.push_front (&_selection_memento->get_state ());
3427 Editor::begin_reversible_selection_op (string name)
3430 //cerr << name << endl;
3431 /* begin/commit pairs can be nested */
3432 selection_op_cmd_depth++;
3437 Editor::commit_reversible_selection_op ()
3440 if (selection_op_cmd_depth == 1) {
3442 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3444 The user has undone some selection ops and then made a new one,
3445 making anything earlier in the list invalid.
3448 list<XMLNode *>::iterator it = selection_op_history.begin();
3449 list<XMLNode *>::iterator e_it = it;
3450 advance (e_it, selection_op_history_it);
3452 for ( ; it != e_it; ++it) {
3455 selection_op_history.erase (selection_op_history.begin(), e_it);
3458 selection_op_history.push_front (&_selection_memento->get_state ());
3459 selection_op_history_it = 0;
3461 selection_undo_action->set_sensitive (true);
3462 selection_redo_action->set_sensitive (false);
3465 if (selection_op_cmd_depth > 0) {
3466 selection_op_cmd_depth--;
3472 Editor::undo_selection_op ()
3475 selection_op_history_it++;
3477 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3478 if (n == selection_op_history_it) {
3479 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3480 selection_redo_action->set_sensitive (true);
3484 /* is there an earlier entry? */
3485 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3486 selection_undo_action->set_sensitive (false);
3492 Editor::redo_selection_op ()
3495 if (selection_op_history_it > 0) {
3496 selection_op_history_it--;
3499 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3500 if (n == selection_op_history_it) {
3501 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3502 selection_undo_action->set_sensitive (true);
3507 if (selection_op_history_it == 0) {
3508 selection_redo_action->set_sensitive (false);
3514 Editor::begin_reversible_command (string name)
3517 before.push_back (&_selection_memento->get_state ());
3518 _session->begin_reversible_command (name);
3523 Editor::begin_reversible_command (GQuark q)
3526 before.push_back (&_selection_memento->get_state ());
3527 _session->begin_reversible_command (q);
3532 Editor::abort_reversible_command ()
3535 while(!before.empty()) {
3536 delete before.front();
3539 _session->abort_reversible_command ();
3544 Editor::commit_reversible_command ()
3547 if (before.size() == 1) {
3548 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3549 redo_action->set_sensitive(false);
3550 undo_action->set_sensitive(true);
3551 begin_selection_op_history ();
3554 if (before.empty()) {
3555 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3560 _session->commit_reversible_command ();
3565 Editor::history_changed ()
3569 if (undo_action && _session) {
3570 if (_session->undo_depth() == 0) {
3571 label = S_("Command|Undo");
3573 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3575 undo_action->property_label() = label;
3578 if (redo_action && _session) {
3579 if (_session->redo_depth() == 0) {
3581 redo_action->set_sensitive (false);
3583 label = string_compose(_("Redo (%1)"), _session->next_redo());
3584 redo_action->set_sensitive (true);
3586 redo_action->property_label() = label;
3591 Editor::duplicate_range (bool with_dialog)
3595 RegionSelection rs = get_regions_from_selection_and_entered ();
3597 if ( selection->time.length() == 0 && rs.empty()) {
3603 ArdourDialog win (_("Duplicate"));
3604 Label label (_("Number of duplications:"));
3605 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3606 SpinButton spinner (adjustment, 0.0, 1);
3609 win.get_vbox()->set_spacing (12);
3610 win.get_vbox()->pack_start (hbox);
3611 hbox.set_border_width (6);
3612 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3614 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3615 place, visually. so do this by hand.
3618 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3619 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3620 spinner.grab_focus();
3626 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3627 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3628 win.set_default_response (RESPONSE_ACCEPT);
3630 spinner.grab_focus ();
3632 switch (win.run ()) {
3633 case RESPONSE_ACCEPT:
3639 times = adjustment.get_value();
3642 if ((current_mouse_mode() == Editing::MouseRange)) {
3643 if (selection->time.length()) {
3644 duplicate_selection (times);
3646 } else if (get_smart_mode()) {
3647 if (selection->time.length()) {
3648 duplicate_selection (times);
3650 duplicate_some_regions (rs, times);
3652 duplicate_some_regions (rs, times);
3657 Editor::set_edit_mode (EditMode m)
3659 Config->set_edit_mode (m);
3663 Editor::cycle_edit_mode ()
3665 switch (Config->get_edit_mode()) {
3667 Config->set_edit_mode (Ripple);
3671 Config->set_edit_mode (Lock);
3674 Config->set_edit_mode (Slide);
3680 Editor::edit_mode_selection_done ( EditMode m )
3682 Config->set_edit_mode ( m );
3686 Editor::snap_type_selection_done (SnapType snaptype)
3688 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3690 ract->set_active ();
3695 Editor::snap_mode_selection_done (SnapMode mode)
3697 RefPtr<RadioAction> ract = snap_mode_action (mode);
3700 ract->set_active (true);
3705 Editor::cycle_edit_point (bool with_marker)
3707 if(Profile->get_mixbus())
3708 with_marker = false;
3710 switch (_edit_point) {
3712 set_edit_point_preference (EditAtPlayhead);
3714 case EditAtPlayhead:
3716 set_edit_point_preference (EditAtSelectedMarker);
3718 set_edit_point_preference (EditAtMouse);
3721 case EditAtSelectedMarker:
3722 set_edit_point_preference (EditAtMouse);
3728 Editor::edit_point_selection_done (EditPoint ep)
3730 set_edit_point_preference ( ep );
3734 Editor::build_zoom_focus_menu ()
3736 using namespace Menu_Helpers;
3738 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3739 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3740 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3741 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3742 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3743 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3745 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3749 Editor::zoom_focus_selection_done ( ZoomFocus f )
3751 RefPtr<RadioAction> ract = zoom_focus_action (f);
3753 ract->set_active ();
3758 Editor::build_track_count_menu ()
3760 using namespace Menu_Helpers;
3762 if (!Profile->get_mixbus()) {
3763 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3764 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3765 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3766 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3767 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3768 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3769 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3770 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3771 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3772 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3773 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3774 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3775 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3777 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3778 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3779 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3780 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3781 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3782 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3783 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3784 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3785 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3786 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3788 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3789 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3790 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3791 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3792 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3793 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3794 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3795 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3796 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3797 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3798 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3803 Editor::set_zoom_preset (int64_t ms)
3806 temporal_zoom_session();
3810 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3811 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3815 Editor::set_visible_track_count (int32_t n)
3817 _visible_track_count = n;
3819 /* if the canvas hasn't really been allocated any size yet, just
3820 record the desired number of visible tracks and return. when canvas
3821 allocation happens, we will get called again and then we can do the
3825 if (_visible_canvas_height <= 1) {
3831 DisplaySuspender ds;
3833 if (_visible_track_count > 0) {
3834 h = trackviews_height() / _visible_track_count;
3835 std::ostringstream s;
3836 s << _visible_track_count;
3838 } else if (_visible_track_count == 0) {
3840 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3841 if ((*i)->marked_for_display()) {
3845 h = trackviews_height() / n;
3848 /* negative value means that the visible track count has
3849 been overridden by explicit track height changes.
3851 visible_tracks_selector.set_text (X_("*"));
3855 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3856 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3859 if (str != visible_tracks_selector.get_text()) {
3860 visible_tracks_selector.set_text (str);
3865 Editor::override_visible_track_count ()
3867 _visible_track_count = -1;
3868 visible_tracks_selector.set_text ( _("*") );
3872 Editor::edit_controls_button_release (GdkEventButton* ev)
3874 if (Keyboard::is_context_menu_event (ev)) {
3875 ARDOUR_UI::instance()->add_route ();
3876 } else if (ev->button == 1) {
3877 selection->clear_tracks ();
3884 Editor::mouse_select_button_release (GdkEventButton* ev)
3886 /* this handles just right-clicks */
3888 if (ev->button != 3) {
3896 Editor::set_zoom_focus (ZoomFocus f)
3898 string str = zoom_focus_strings[(int)f];
3900 if (str != zoom_focus_selector.get_text()) {
3901 zoom_focus_selector.set_text (str);
3904 if (zoom_focus != f) {
3911 Editor::cycle_zoom_focus ()
3913 switch (zoom_focus) {
3915 set_zoom_focus (ZoomFocusRight);
3917 case ZoomFocusRight:
3918 set_zoom_focus (ZoomFocusCenter);
3920 case ZoomFocusCenter:
3921 set_zoom_focus (ZoomFocusPlayhead);
3923 case ZoomFocusPlayhead:
3924 set_zoom_focus (ZoomFocusMouse);
3926 case ZoomFocusMouse:
3927 set_zoom_focus (ZoomFocusEdit);
3930 set_zoom_focus (ZoomFocusLeft);
3936 Editor::set_show_measures (bool yn)
3938 if (_show_measures != yn) {
3941 if ((_show_measures = yn) == true) {
3943 tempo_lines->show();
3946 std::vector<TempoMap::BBTPoint> grid;
3947 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3948 draw_measures (grid);
3956 Editor::toggle_follow_playhead ()
3958 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3960 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3961 set_follow_playhead (tact->get_active());
3965 /** @param yn true to follow playhead, otherwise false.
3966 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3969 Editor::set_follow_playhead (bool yn, bool catch_up)
3971 if (_follow_playhead != yn) {
3972 if ((_follow_playhead = yn) == true && catch_up) {
3974 reset_x_origin_to_follow_playhead ();
3981 Editor::toggle_stationary_playhead ()
3983 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3985 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3986 set_stationary_playhead (tact->get_active());
3991 Editor::set_stationary_playhead (bool yn)
3993 if (_stationary_playhead != yn) {
3994 if ((_stationary_playhead = yn) == true) {
3996 // FIXME need a 3.0 equivalent of this 2.X call
3997 // update_current_screen ();
4004 Editor::playlist_selector () const
4006 return *_playlist_selector;
4010 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4012 if (paste_count == 0) {
4013 /* don't bother calculating an offset that will be zero anyway */
4017 /* calculate basic unsnapped multi-paste offset */
4018 framecnt_t offset = paste_count * duration;
4020 /* snap offset so pos + offset is aligned to the grid */
4021 framepos_t offset_pos = pos + offset;
4022 snap_to(offset_pos, RoundUpMaybe);
4023 offset = offset_pos - pos;
4029 Editor::get_grid_beat_divisions(framepos_t position)
4031 switch (_snap_type) {
4032 case SnapToBeatDiv128: return 128;
4033 case SnapToBeatDiv64: return 64;
4034 case SnapToBeatDiv32: return 32;
4035 case SnapToBeatDiv28: return 28;
4036 case SnapToBeatDiv24: return 24;
4037 case SnapToBeatDiv20: return 20;
4038 case SnapToBeatDiv16: return 16;
4039 case SnapToBeatDiv14: return 14;
4040 case SnapToBeatDiv12: return 12;
4041 case SnapToBeatDiv10: return 10;
4042 case SnapToBeatDiv8: return 8;
4043 case SnapToBeatDiv7: return 7;
4044 case SnapToBeatDiv6: return 6;
4045 case SnapToBeatDiv5: return 5;
4046 case SnapToBeatDiv4: return 4;
4047 case SnapToBeatDiv3: return 3;
4048 case SnapToBeatDiv2: return 2;
4054 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4055 if the grid is non-musical, returns 0.
4056 if the grid is snapped to bars, returns -1.
4057 @param event_state the current keyboard modifier mask.
4060 Editor::get_grid_music_divisions (uint32_t event_state)
4062 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4066 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4070 switch (_snap_type) {
4071 case SnapToBeatDiv128: return 128;
4072 case SnapToBeatDiv64: return 64;
4073 case SnapToBeatDiv32: return 32;
4074 case SnapToBeatDiv28: return 28;
4075 case SnapToBeatDiv24: return 24;
4076 case SnapToBeatDiv20: return 20;
4077 case SnapToBeatDiv16: return 16;
4078 case SnapToBeatDiv14: return 14;
4079 case SnapToBeatDiv12: return 12;
4080 case SnapToBeatDiv10: return 10;
4081 case SnapToBeatDiv8: return 8;
4082 case SnapToBeatDiv7: return 7;
4083 case SnapToBeatDiv6: return 6;
4084 case SnapToBeatDiv5: return 5;
4085 case SnapToBeatDiv4: return 4;
4086 case SnapToBeatDiv3: return 3;
4087 case SnapToBeatDiv2: return 2;
4088 case SnapToBeat: return 1;
4089 case SnapToBar : return -1;
4096 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4100 const unsigned divisions = get_grid_beat_divisions(position);
4102 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4105 switch (_snap_type) {
4107 return Evoral::Beats(1.0);
4110 return Evoral::Beats(_session->tempo_map().meter_at_frame (position).divisions_per_bar());
4118 return Evoral::Beats();
4122 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4126 ret = nudge_clock->current_duration (pos);
4127 next = ret + 1; /* XXXX fix me */
4133 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4135 ArdourDialog dialog (_("Playlist Deletion"));
4136 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4137 "If it is kept, its audio files will not be cleaned.\n"
4138 "If it is deleted, audio files used by it alone will be cleaned."),
4141 dialog.set_position (WIN_POS_CENTER);
4142 dialog.get_vbox()->pack_start (label);
4146 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4147 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4148 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4149 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4150 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4152 // by default gtk uses the left most button
4153 keep->grab_focus ();
4155 switch (dialog.run ()) {
4157 /* keep this and all remaining ones */
4162 /* delete this and all others */
4166 case RESPONSE_ACCEPT:
4167 /* delete the playlist */
4171 case RESPONSE_REJECT:
4172 /* keep the playlist */
4184 Editor::audio_region_selection_covers (framepos_t where)
4186 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4187 if ((*a)->region()->covers (where)) {
4196 Editor::prepare_for_cleanup ()
4198 cut_buffer->clear_regions ();
4199 cut_buffer->clear_playlists ();
4201 selection->clear_regions ();
4202 selection->clear_playlists ();
4204 _regions->suspend_redisplay ();
4208 Editor::finish_cleanup ()
4210 _regions->resume_redisplay ();
4214 Editor::transport_loop_location()
4217 return _session->locations()->auto_loop_location();
4224 Editor::transport_punch_location()
4227 return _session->locations()->auto_punch_location();
4234 Editor::control_layout_scroll (GdkEventScroll* ev)
4236 /* Just forward to the normal canvas scroll method. The coordinate
4237 systems are different but since the canvas is always larger than the
4238 track headers, and aligned with the trackview area, this will work.
4240 In the not too distant future this layout is going away anyway and
4241 headers will be on the canvas.
4243 return canvas_scroll_event (ev, false);
4247 Editor::session_state_saved (string)
4250 _snapshots->redisplay ();
4254 Editor::maximise_editing_space ()
4260 Gtk::Window* toplevel = current_toplevel();
4263 toplevel->fullscreen ();
4269 Editor::restore_editing_space ()
4275 Gtk::Window* toplevel = current_toplevel();
4278 toplevel->unfullscreen();
4284 * Make new playlists for a given track and also any others that belong
4285 * to the same active route group with the `select' property.
4290 Editor::new_playlists (TimeAxisView* v)
4292 begin_reversible_command (_("new playlists"));
4293 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4294 _session->playlists->get (playlists);
4295 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4296 commit_reversible_command ();
4300 * Use a copy of the current playlist for a given track and also any others that belong
4301 * to the same active route group with the `select' property.
4306 Editor::copy_playlists (TimeAxisView* v)
4308 begin_reversible_command (_("copy 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_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4312 commit_reversible_command ();
4315 /** Clear the current playlist for a given track and also any others that belong
4316 * to the same active route group with the `select' property.
4321 Editor::clear_playlists (TimeAxisView* v)
4323 begin_reversible_command (_("clear playlists"));
4324 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4325 _session->playlists->get (playlists);
4326 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4327 commit_reversible_command ();
4331 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4333 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4337 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4339 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4343 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4345 atv.clear_playlist ();
4349 Editor::get_y_origin () const
4351 return vertical_adjustment.get_value ();
4354 /** Queue up a change to the viewport x origin.
4355 * @param frame New x origin.
4358 Editor::reset_x_origin (framepos_t frame)
4360 pending_visual_change.add (VisualChange::TimeOrigin);
4361 pending_visual_change.time_origin = frame;
4362 ensure_visual_change_idle_handler ();
4366 Editor::reset_y_origin (double y)
4368 pending_visual_change.add (VisualChange::YOrigin);
4369 pending_visual_change.y_origin = y;
4370 ensure_visual_change_idle_handler ();
4374 Editor::reset_zoom (framecnt_t spp)
4376 if (spp == samples_per_pixel) {
4380 pending_visual_change.add (VisualChange::ZoomLevel);
4381 pending_visual_change.samples_per_pixel = spp;
4382 ensure_visual_change_idle_handler ();
4386 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4388 reset_x_origin (frame);
4391 if (!no_save_visual) {
4392 undo_visual_stack.push_back (current_visual_state(false));
4396 Editor::VisualState::VisualState (bool with_tracks)
4397 : gui_state (with_tracks ? new GUIObjectState : 0)
4401 Editor::VisualState::~VisualState ()
4406 Editor::VisualState*
4407 Editor::current_visual_state (bool with_tracks)
4409 VisualState* vs = new VisualState (with_tracks);
4410 vs->y_position = vertical_adjustment.get_value();
4411 vs->samples_per_pixel = samples_per_pixel;
4412 vs->leftmost_frame = leftmost_frame;
4413 vs->zoom_focus = zoom_focus;
4416 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4423 Editor::undo_visual_state ()
4425 if (undo_visual_stack.empty()) {
4429 VisualState* vs = undo_visual_stack.back();
4430 undo_visual_stack.pop_back();
4433 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4436 use_visual_state (*vs);
4441 Editor::redo_visual_state ()
4443 if (redo_visual_stack.empty()) {
4447 VisualState* vs = redo_visual_stack.back();
4448 redo_visual_stack.pop_back();
4450 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4451 // why do we check here?
4452 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4455 use_visual_state (*vs);
4460 Editor::swap_visual_state ()
4462 if (undo_visual_stack.empty()) {
4463 redo_visual_state ();
4465 undo_visual_state ();
4470 Editor::use_visual_state (VisualState& vs)
4472 PBD::Unwinder<bool> nsv (no_save_visual, true);
4473 DisplaySuspender ds;
4475 vertical_adjustment.set_value (vs.y_position);
4477 set_zoom_focus (vs.zoom_focus);
4478 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4481 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4483 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4484 (*i)->clear_property_cache();
4485 (*i)->reset_visual_state ();
4489 _routes->update_visibility ();
4492 /** This is the core function that controls the zoom level of the canvas. It is called
4493 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4494 * @param spp new number of samples per pixel
4497 Editor::set_samples_per_pixel (framecnt_t spp)
4503 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4504 const framecnt_t lots_of_pixels = 4000;
4506 /* if the zoom level is greater than what you'd get trying to display 3
4507 * days of audio on a really big screen, then it's too big.
4510 if (spp * lots_of_pixels > three_days) {
4514 samples_per_pixel = spp;
4517 tempo_lines->tempo_map_changed();
4520 bool const showing_time_selection = selection->time.length() > 0;
4522 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4523 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4524 (*i)->reshow_selection (selection->time);
4528 ZoomChanged (); /* EMIT_SIGNAL */
4530 ArdourCanvas::GtkCanvasViewport* c;
4532 c = get_track_canvas();
4534 c->canvas()->zoomed ();
4537 if (playhead_cursor) {
4538 playhead_cursor->set_position (playhead_cursor->current_frame ());
4541 refresh_location_display();
4542 _summary->set_overlays_dirty ();
4544 update_marker_labels ();
4550 Editor::queue_visual_videotimeline_update ()
4553 * pending_visual_change.add (VisualChange::VideoTimeline);
4554 * or maybe even more specific: which videotimeline-image
4555 * currently it calls update_video_timeline() to update
4556 * _all outdated_ images on the video-timeline.
4557 * see 'exposeimg()' in video_image_frame.cc
4559 ensure_visual_change_idle_handler ();
4563 Editor::ensure_visual_change_idle_handler ()
4565 if (pending_visual_change.idle_handler_id < 0) {
4566 // see comment in add_to_idle_resize above.
4567 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4568 pending_visual_change.being_handled = false;
4573 Editor::_idle_visual_changer (void* arg)
4575 return static_cast<Editor*>(arg)->idle_visual_changer ();
4579 Editor::idle_visual_changer ()
4581 /* set_horizontal_position() below (and maybe other calls) call
4582 gtk_main_iteration(), so it's possible that a signal will be handled
4583 half-way through this method. If this signal wants an
4584 idle_visual_changer we must schedule another one after this one, so
4585 mark the idle_handler_id as -1 here to allow that. Also make a note
4586 that we are doing the visual change, so that changes in response to
4587 super-rapid-screen-update can be dropped if we are still processing
4591 pending_visual_change.idle_handler_id = -1;
4592 pending_visual_change.being_handled = true;
4594 VisualChange vc = pending_visual_change;
4596 pending_visual_change.pending = (VisualChange::Type) 0;
4598 visual_changer (vc);
4600 pending_visual_change.being_handled = false;
4602 return 0; /* this is always a one-shot call */
4606 Editor::visual_changer (const VisualChange& vc)
4608 double const last_time_origin = horizontal_position ();
4610 if (vc.pending & VisualChange::ZoomLevel) {
4611 set_samples_per_pixel (vc.samples_per_pixel);
4613 compute_fixed_ruler_scale ();
4615 std::vector<TempoMap::BBTPoint> grid;
4616 compute_current_bbt_points (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4617 compute_bbt_ruler_scale (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4618 update_tempo_based_rulers (grid);
4620 update_video_timeline();
4623 if (vc.pending & VisualChange::TimeOrigin) {
4624 set_horizontal_position (vc.time_origin / samples_per_pixel);
4627 if (vc.pending & VisualChange::YOrigin) {
4628 vertical_adjustment.set_value (vc.y_origin);
4631 if (last_time_origin == horizontal_position ()) {
4632 /* changed signal not emitted */
4633 update_fixed_rulers ();
4634 redisplay_tempo (true);
4637 if (!(vc.pending & VisualChange::ZoomLevel)) {
4638 update_video_timeline();
4641 _summary->set_overlays_dirty ();
4644 struct EditorOrderTimeAxisSorter {
4645 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4646 return a->order () < b->order ();
4651 Editor::sort_track_selection (TrackViewList& sel)
4653 EditorOrderTimeAxisSorter cmp;
4658 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4661 framepos_t where = 0;
4662 EditPoint ep = _edit_point;
4664 if (Profile->get_mixbus())
4665 if (ep == EditAtSelectedMarker)
4666 ep = EditAtPlayhead;
4668 if (from_outside_canvas && (ep == EditAtMouse)) {
4669 ep = EditAtPlayhead;
4670 } else if (from_context_menu && (ep == EditAtMouse)) {
4671 return canvas_event_sample (&context_click_event, 0, 0);
4674 if (entered_marker) {
4675 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4676 return entered_marker->position();
4679 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4680 ep = EditAtSelectedMarker;
4683 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4684 ep = EditAtPlayhead;
4688 case EditAtPlayhead:
4689 if (_dragging_playhead) {
4690 where = *_control_scroll_target;
4692 where = _session->audible_frame();
4694 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4697 case EditAtSelectedMarker:
4698 if (!selection->markers.empty()) {
4700 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4703 where = loc->start();
4707 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4715 if (!mouse_frame (where, ignored)) {
4716 /* XXX not right but what can we do ? */
4720 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4728 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4730 if (!_session) return;
4732 begin_reversible_command (cmd);
4736 if ((tll = transport_loop_location()) == 0) {
4737 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4738 XMLNode &before = _session->locations()->get_state();
4739 _session->locations()->add (loc, true);
4740 _session->set_auto_loop_location (loc);
4741 XMLNode &after = _session->locations()->get_state();
4742 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4744 XMLNode &before = tll->get_state();
4745 tll->set_hidden (false, this);
4746 tll->set (start, end);
4747 XMLNode &after = tll->get_state();
4748 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4751 commit_reversible_command ();
4755 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4757 if (!_session) return;
4759 begin_reversible_command (cmd);
4763 if ((tpl = transport_punch_location()) == 0) {
4764 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4765 XMLNode &before = _session->locations()->get_state();
4766 _session->locations()->add (loc, true);
4767 _session->set_auto_punch_location (loc);
4768 XMLNode &after = _session->locations()->get_state();
4769 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4771 XMLNode &before = tpl->get_state();
4772 tpl->set_hidden (false, this);
4773 tpl->set (start, end);
4774 XMLNode &after = tpl->get_state();
4775 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4778 commit_reversible_command ();
4781 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4782 * @param rs List to which found regions are added.
4783 * @param where Time to look at.
4784 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4787 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4789 const TrackViewList* tracks;
4792 tracks = &track_views;
4797 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4799 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4802 boost::shared_ptr<Track> tr;
4803 boost::shared_ptr<Playlist> pl;
4805 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4807 boost::shared_ptr<RegionList> regions = pl->regions_at (
4808 (framepos_t) floor ( (double) where * tr->speed()));
4810 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4811 RegionView* rv = rtv->view()->find_view (*i);
4822 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4824 const TrackViewList* tracks;
4827 tracks = &track_views;
4832 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4833 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4835 boost::shared_ptr<Track> tr;
4836 boost::shared_ptr<Playlist> pl;
4838 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4840 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4841 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4843 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4845 RegionView* rv = rtv->view()->find_view (*i);
4856 /** Get regions using the following method:
4858 * Make a region list using:
4859 * (a) any selected regions
4860 * (b) the intersection of any selected tracks and the edit point(*)
4861 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4863 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4865 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4869 Editor::get_regions_from_selection_and_edit_point ()
4871 RegionSelection regions;
4873 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4874 regions.add (entered_regionview);
4876 regions = selection->regions;
4879 if ( regions.empty() ) {
4880 TrackViewList tracks = selection->tracks;
4882 if (!tracks.empty()) {
4883 /* no region selected or entered, but some selected tracks:
4884 * act on all regions on the selected tracks at the edit point
4886 framepos_t const where = get_preferred_edit_position ();
4887 get_regions_at(regions, where, tracks);
4894 /** Get regions using the following method:
4896 * Make a region list using:
4897 * (a) any selected regions
4898 * (b) the intersection of any selected tracks and the edit point(*)
4899 * (c) if neither exists, then whatever region is under the mouse
4901 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4903 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4906 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4908 RegionSelection regions;
4910 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4911 regions.add (entered_regionview);
4913 regions = selection->regions;
4916 if ( regions.empty() ) {
4917 TrackViewList tracks = selection->tracks;
4919 if (!tracks.empty()) {
4920 /* no region selected or entered, but some selected tracks:
4921 * act on all regions on the selected tracks at the edit point
4923 get_regions_at(regions, pos, tracks);
4930 /** Start with regions that are selected, or the entered regionview if none are selected.
4931 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4932 * of the regions that we started with.
4936 Editor::get_regions_from_selection_and_entered () const
4938 RegionSelection regions = selection->regions;
4940 if (regions.empty() && entered_regionview) {
4941 regions.add (entered_regionview);
4948 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4950 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4951 RouteTimeAxisView* rtav;
4953 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4954 boost::shared_ptr<Playlist> pl;
4955 std::vector<boost::shared_ptr<Region> > results;
4956 boost::shared_ptr<Track> tr;
4958 if ((tr = rtav->track()) == 0) {
4963 if ((pl = (tr->playlist())) != 0) {
4964 boost::shared_ptr<Region> r = pl->region_by_id (id);
4966 RegionView* rv = rtav->view()->find_view (r);
4968 regions.push_back (rv);
4977 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4980 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4981 MidiTimeAxisView* mtav;
4983 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4985 mtav->get_per_region_note_selection (selection);
4992 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4994 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4996 RouteTimeAxisView* tatv;
4998 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5000 boost::shared_ptr<Playlist> pl;
5001 vector<boost::shared_ptr<Region> > results;
5003 boost::shared_ptr<Track> tr;
5005 if ((tr = tatv->track()) == 0) {
5010 if ((pl = (tr->playlist())) != 0) {
5011 if (src_comparison) {
5012 pl->get_source_equivalent_regions (region, results);
5014 pl->get_region_list_equivalent_regions (region, results);
5018 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5019 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5020 regions.push_back (marv);
5029 Editor::show_rhythm_ferret ()
5031 if (rhythm_ferret == 0) {
5032 rhythm_ferret = new RhythmFerret(*this);
5035 rhythm_ferret->set_session (_session);
5036 rhythm_ferret->show ();
5037 rhythm_ferret->present ();
5041 Editor::first_idle ()
5043 MessageDialog* dialog = 0;
5045 if (track_views.size() > 1) {
5046 Timers::TimerSuspender t;
5047 dialog = new MessageDialog (
5048 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5052 ARDOUR_UI::instance()->flush_pending ();
5055 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5059 // first idle adds route children (automation tracks), so we need to redisplay here
5060 _routes->redisplay ();
5064 if (_session->undo_depth() == 0) {
5065 undo_action->set_sensitive(false);
5067 redo_action->set_sensitive(false);
5068 begin_selection_op_history ();
5074 Editor::_idle_resize (gpointer arg)
5076 return ((Editor*)arg)->idle_resize ();
5080 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5082 if (resize_idle_id < 0) {
5083 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5084 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5085 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5087 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5088 _pending_resize_amount = 0;
5091 /* make a note of the smallest resulting height, so that we can clamp the
5092 lower limit at TimeAxisView::hSmall */
5094 int32_t min_resulting = INT32_MAX;
5096 _pending_resize_amount += h;
5097 _pending_resize_view = view;
5099 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5101 if (selection->tracks.contains (_pending_resize_view)) {
5102 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5103 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5107 if (min_resulting < 0) {
5112 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5113 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5117 /** Handle pending resizing of tracks */
5119 Editor::idle_resize ()
5121 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5123 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5124 selection->tracks.contains (_pending_resize_view)) {
5126 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5127 if (*i != _pending_resize_view) {
5128 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5133 _pending_resize_amount = 0;
5134 _group_tabs->set_dirty ();
5135 resize_idle_id = -1;
5143 ENSURE_GUI_THREAD (*this, &Editor::located);
5146 playhead_cursor->set_position (_session->audible_frame ());
5147 if (_follow_playhead && !_pending_initial_locate) {
5148 reset_x_origin_to_follow_playhead ();
5152 _pending_locate_request = false;
5153 _pending_initial_locate = false;
5157 Editor::region_view_added (RegionView * rv)
5159 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5160 if (rv->region ()->id () == (*pr)) {
5161 selection->add (rv);
5162 selection->regions.pending.erase (pr);
5167 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5169 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5170 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5171 if (rv->region()->id () == (*rnote).first) {
5172 mrv->select_notes ((*rnote).second);
5173 selection->pending_midi_note_selection.erase(rnote);
5179 _summary->set_background_dirty ();
5183 Editor::region_view_removed ()
5185 _summary->set_background_dirty ();
5189 Editor::axis_view_from_stripable (boost::shared_ptr<Stripable> s) const
5191 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5192 if ((*j)->stripable() == s) {
5202 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5206 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5207 TimeAxisView* tv = axis_view_from_stripable (*i);
5217 Editor::suspend_route_redisplay ()
5220 _routes->suspend_redisplay();
5225 Editor::resume_route_redisplay ()
5228 _routes->redisplay(); // queue redisplay
5229 _routes->resume_redisplay();
5234 Editor::add_vcas (VCAList& vlist)
5238 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5239 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5242 add_stripables (sl);
5246 Editor::add_routes (RouteList& rlist)
5250 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5254 add_stripables (sl);
5258 Editor::add_stripables (StripableList& sl)
5260 list<TimeAxisView*> new_views;
5261 boost::shared_ptr<VCA> v;
5262 boost::shared_ptr<Route> r;
5263 TrackViewList new_selection;
5264 bool from_scratch = (track_views.size() == 0);
5266 sl.sort (StripablePresentationInfoSorter());
5268 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5270 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5272 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5274 new_views.push_back (vtv);
5276 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5278 if (r->is_auditioner() || r->is_monitor()) {
5282 RouteTimeAxisView* rtv;
5283 DataType dt = r->input()->default_type();
5285 if (dt == ARDOUR::DataType::AUDIO) {
5286 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5288 } else if (dt == ARDOUR::DataType::MIDI) {
5289 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5292 throw unknown_type();
5295 new_views.push_back (rtv);
5296 track_views.push_back (rtv);
5297 new_selection.push_back (rtv);
5299 rtv->effective_gain_display ();
5301 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5302 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5306 if (new_views.size() > 0) {
5307 _routes->time_axis_views_added (new_views);
5308 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5311 /* note: !new_selection.empty() means that we got some routes rather
5315 if (!from_scratch && !new_selection.empty()) {
5316 selection->tracks.clear();
5317 selection->add (new_selection);
5318 begin_selection_op_history();
5321 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5322 show_editor_mixer (true);
5325 editor_list_button.set_sensitive (true);
5329 Editor::timeaxisview_deleted (TimeAxisView *tv)
5331 if (tv == entered_track) {
5335 if (_session && _session->deletion_in_progress()) {
5336 /* the situation is under control */
5340 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5342 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5344 _routes->route_removed (tv);
5346 TimeAxisView::Children c = tv->get_child_list ();
5347 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5348 if (entered_track == i->get()) {
5353 /* remove it from the list of track views */
5355 TrackViewList::iterator i;
5357 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5358 i = track_views.erase (i);
5361 /* update whatever the current mixer strip is displaying, if revelant */
5363 boost::shared_ptr<Route> route;
5366 route = rtav->route ();
5369 if (current_mixer_strip && current_mixer_strip->route() == route) {
5371 TimeAxisView* next_tv;
5373 if (track_views.empty()) {
5375 } else if (i == track_views.end()) {
5376 next_tv = track_views.front();
5383 set_selected_mixer_strip (*next_tv);
5385 /* make the editor mixer strip go away setting the
5386 * button to inactive (which also unticks the menu option)
5389 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5395 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5397 if (apply_to_selection) {
5398 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5400 TrackSelection::iterator j = i;
5403 hide_track_in_display (*i, false);
5408 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5410 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5411 // this will hide the mixer strip
5412 set_selected_mixer_strip (*tv);
5415 _routes->hide_track_in_display (*tv);
5420 Editor::sync_track_view_list_and_routes ()
5422 track_views = TrackViewList (_routes->views ());
5424 _summary->set_background_dirty();
5425 _group_tabs->set_dirty ();
5427 return false; // do not call again (until needed)
5431 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5433 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5438 /** Find a RouteTimeAxisView by the ID of its route */
5440 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5442 RouteTimeAxisView* v;
5444 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5445 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5446 if(v->route()->id() == id) {
5456 Editor::fit_route_group (RouteGroup *g)
5458 TrackViewList ts = axis_views_from_routes (g->route_list ());
5463 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5465 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5468 _session->cancel_audition ();
5472 if (_session->is_auditioning()) {
5473 _session->cancel_audition ();
5474 if (r == last_audition_region) {
5479 _session->audition_region (r);
5480 last_audition_region = r;
5485 Editor::hide_a_region (boost::shared_ptr<Region> r)
5487 r->set_hidden (true);
5491 Editor::show_a_region (boost::shared_ptr<Region> r)
5493 r->set_hidden (false);
5497 Editor::audition_region_from_region_list ()
5499 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5503 Editor::hide_region_from_region_list ()
5505 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5509 Editor::show_region_in_region_list ()
5511 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5515 Editor::step_edit_status_change (bool yn)
5518 start_step_editing ();
5520 stop_step_editing ();
5525 Editor::start_step_editing ()
5527 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5531 Editor::stop_step_editing ()
5533 step_edit_connection.disconnect ();
5537 Editor::check_step_edit ()
5539 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5540 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5542 mtv->check_step_edit ();
5546 return true; // do it again, till we stop
5550 Editor::scroll_press (Direction dir)
5552 ++_scroll_callbacks;
5554 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5555 /* delay the first auto-repeat */
5561 scroll_backward (1);
5569 scroll_up_one_track ();
5573 scroll_down_one_track ();
5577 /* do hacky auto-repeat */
5578 if (!_scroll_connection.connected ()) {
5580 _scroll_connection = Glib::signal_timeout().connect (
5581 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5584 _scroll_callbacks = 0;
5591 Editor::scroll_release ()
5593 _scroll_connection.disconnect ();
5596 /** Queue a change for the Editor viewport x origin to follow the playhead */
5598 Editor::reset_x_origin_to_follow_playhead ()
5600 framepos_t const frame = playhead_cursor->current_frame ();
5602 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5604 if (_session->transport_speed() < 0) {
5606 if (frame > (current_page_samples() / 2)) {
5607 center_screen (frame-(current_page_samples()/2));
5609 center_screen (current_page_samples()/2);
5616 if (frame < leftmost_frame) {
5618 if (_session->transport_rolling()) {
5619 /* rolling; end up with the playhead at the right of the page */
5620 l = frame - current_page_samples ();
5622 /* not rolling: end up with the playhead 1/4 of the way along the page */
5623 l = frame - current_page_samples() / 4;
5627 if (_session->transport_rolling()) {
5628 /* rolling: end up with the playhead on the left of the page */
5631 /* not rolling: end up with the playhead 3/4 of the way along the page */
5632 l = frame - 3 * current_page_samples() / 4;
5640 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5646 Editor::super_rapid_screen_update ()
5648 if (!_session || !_session->engine().running()) {
5652 /* METERING / MIXER STRIPS */
5654 /* update track meters, if required */
5655 if (contents().is_mapped() && meters_running) {
5656 RouteTimeAxisView* rtv;
5657 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5658 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5659 rtv->fast_update ();
5664 /* and any current mixer strip */
5665 if (current_mixer_strip) {
5666 current_mixer_strip->fast_update ();
5669 /* PLAYHEAD AND VIEWPORT */
5671 framepos_t const frame = _session->audible_frame();
5673 /* There are a few reasons why we might not update the playhead / viewport stuff:
5675 * 1. we don't update things when there's a pending locate request, otherwise
5676 * when the editor requests a locate there is a chance that this method
5677 * will move the playhead before the locate request is processed, causing
5679 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5680 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5683 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5685 last_update_frame = frame;
5687 if (!_dragging_playhead) {
5688 playhead_cursor->set_position (frame);
5691 if (!_stationary_playhead) {
5693 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5694 /* We only do this if we aren't already
5695 handling a visual change (ie if
5696 pending_visual_change.being_handled is
5697 false) so that these requests don't stack
5698 up there are too many of them to handle in
5701 reset_x_origin_to_follow_playhead ();
5706 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5707 framepos_t const frame = playhead_cursor->current_frame ();
5708 double target = ((double)frame - (double)current_page_samples()/2.0);
5709 if (target <= 0.0) {
5712 // compare to EditorCursor::set_position()
5713 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5714 double const new_pos = sample_to_pixel_unrounded (target);
5715 if (rint (new_pos) != rint (old_pos)) {
5716 reset_x_origin (pixel_to_sample (floor (new_pos)));
5727 Editor::session_going_away ()
5729 _have_idled = false;
5731 _session_connections.drop_connections ();
5733 super_rapid_screen_update_connection.disconnect ();
5735 selection->clear ();
5736 cut_buffer->clear ();
5738 clicked_regionview = 0;
5739 clicked_axisview = 0;
5740 clicked_routeview = 0;
5741 entered_regionview = 0;
5743 last_update_frame = 0;
5746 playhead_cursor->hide ();
5748 /* rip everything out of the list displays */
5752 _route_groups->clear ();
5754 /* do this first so that deleting a track doesn't reset cms to null
5755 and thus cause a leak.
5758 if (current_mixer_strip) {
5759 if (current_mixer_strip->get_parent() != 0) {
5760 global_hpacker.remove (*current_mixer_strip);
5762 delete current_mixer_strip;
5763 current_mixer_strip = 0;
5766 /* delete all trackviews */
5768 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5771 track_views.clear ();
5773 nudge_clock->set_session (0);
5775 editor_list_button.set_active(false);
5776 editor_list_button.set_sensitive(false);
5778 /* clear tempo/meter rulers */
5779 remove_metric_marks ();
5781 clear_marker_display ();
5783 stop_step_editing ();
5787 /* get rid of any existing editor mixer strip */
5789 WindowTitle title(Glib::get_application_name());
5790 title += _("Editor");
5792 own_window()->set_title (title.get_string());
5795 SessionHandlePtr::session_going_away ();
5799 Editor::trigger_script (int i)
5801 LuaInstance::instance()-> call_action (i);
5805 Editor::set_script_action_name (int i, const std::string& n)
5807 string const a = string_compose (X_("script-action-%1"), i + 1);
5808 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5811 act->set_label (string_compose (_("Unset #%1"), i + 1));
5812 act->set_tooltip (_("no action bound"));
5813 act->set_sensitive (false);
5816 act->set_tooltip (n);
5817 act->set_sensitive (true);
5819 KeyEditor::UpdateBindings ();
5823 Editor::show_editor_list (bool yn)
5826 _the_notebook.show ();
5828 _the_notebook.hide ();
5833 Editor::change_region_layering_order (bool from_context_menu)
5835 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5837 if (!clicked_routeview) {
5838 if (layering_order_editor) {
5839 layering_order_editor->hide ();
5844 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5850 boost::shared_ptr<Playlist> pl = track->playlist();
5856 if (layering_order_editor == 0) {
5857 layering_order_editor = new RegionLayeringOrderEditor (*this);
5860 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5861 layering_order_editor->maybe_present ();
5865 Editor::update_region_layering_order_editor ()
5867 if (layering_order_editor && layering_order_editor->is_visible ()) {
5868 change_region_layering_order (true);
5873 Editor::setup_fade_images ()
5875 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5876 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5877 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5878 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5879 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5881 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5882 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5883 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5884 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5885 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5887 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5888 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5889 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5890 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5891 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5893 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5894 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5895 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5896 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5897 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5901 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5903 Editor::action_menu_item (std::string const & name)
5905 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5908 return *manage (a->create_menu_item ());
5912 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5914 EventBox* b = manage (new EventBox);
5915 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5916 Label* l = manage (new Label (name));
5920 _the_notebook.append_page (widget, *b);
5924 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5926 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5927 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5930 if (ev->type == GDK_2BUTTON_PRESS) {
5932 /* double-click on a notebook tab shrinks or expands the notebook */
5934 if (_notebook_shrunk) {
5935 if (pre_notebook_shrink_pane_width) {
5936 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
5938 _notebook_shrunk = false;
5940 pre_notebook_shrink_pane_width = edit_pane.get_divider();
5942 /* this expands the LHS of the edit pane to cover the notebook
5943 PAGE but leaves the tabs visible.
5945 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
5946 _notebook_shrunk = true;
5954 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5956 using namespace Menu_Helpers;
5958 MenuList& items = _control_point_context_menu.items ();
5961 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5962 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5963 if (!can_remove_control_point (item)) {
5964 items.back().set_sensitive (false);
5967 _control_point_context_menu.popup (event->button.button, event->button.time);
5971 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5973 using namespace Menu_Helpers;
5975 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5980 /* We need to get the selection here and pass it to the operations, since
5981 popping up the menu will cause a region leave event which clears
5982 entered_regionview. */
5984 MidiRegionView& mrv = note->region_view();
5985 const RegionSelection rs = get_regions_from_selection_and_entered ();
5986 const uint32_t sel_size = mrv.selection_size ();
5988 MenuList& items = _note_context_menu.items();
5992 items.push_back(MenuElem(_("Delete"),
5993 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5996 items.push_back(MenuElem(_("Edit..."),
5997 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5998 if (sel_size != 1) {
5999 items.back().set_sensitive (false);
6002 items.push_back(MenuElem(_("Transpose..."),
6003 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6006 items.push_back(MenuElem(_("Legatize"),
6007 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6009 items.back().set_sensitive (false);
6012 items.push_back(MenuElem(_("Quantize..."),
6013 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6015 items.push_back(MenuElem(_("Remove Overlap"),
6016 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6018 items.back().set_sensitive (false);
6021 items.push_back(MenuElem(_("Transform..."),
6022 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6024 _note_context_menu.popup (event->button.button, event->button.time);
6028 Editor::zoom_vertical_modifier_released()
6030 _stepping_axis_view = 0;
6034 Editor::ui_parameter_changed (string parameter)
6036 if (parameter == "icon-set") {
6037 while (!_cursor_stack.empty()) {
6038 _cursor_stack.pop_back();
6040 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6041 _cursor_stack.push_back(_cursors->grabber);
6042 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6043 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6045 } else if (parameter == "draggable-playhead") {
6046 if (_verbose_cursor) {
6047 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6053 Editor::use_own_window (bool and_fill_it)
6055 bool new_window = !own_window();
6057 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6059 if (win && new_window) {
6060 win->set_name ("EditorWindow");
6062 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6064 // win->signal_realize().connect (*this, &Editor::on_realize);
6065 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6066 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6067 win->set_data ("ardour-bindings", bindings);
6072 DisplaySuspender ds;
6073 contents().show_all ();
6075 /* XXX: this is a bit unfortunate; it would probably
6076 be nicer if we could just call show () above rather
6077 than needing the show_all ()
6080 /* re-hide stuff if necessary */
6081 editor_list_button_toggled ();
6082 parameter_changed ("show-summary");
6083 parameter_changed ("show-group-tabs");
6084 parameter_changed ("show-zoom-tools");
6086 /* now reset all audio_time_axis heights, because widgets might need
6092 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6093 tv = (static_cast<TimeAxisView*>(*i));
6094 tv->reset_height ();
6097 if (current_mixer_strip) {
6098 current_mixer_strip->hide_things ();
6099 current_mixer_strip->parameter_changed ("mixer-element-visibility");