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"
142 #include "pbd/i18n.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 _verbose_cursor;
871 delete quantize_dialog;
877 delete _playlist_selector;
879 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
885 Editor::button_settings () const
887 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
888 XMLNode* node = find_named_node (*settings, X_("Buttons"));
891 node = new XMLNode (X_("Buttons"));
898 Editor::get_smart_mode () const
900 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
904 Editor::catch_vanishing_regionview (RegionView *rv)
906 /* note: the selection will take care of the vanishing
907 audioregionview by itself.
910 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
914 if (clicked_regionview == rv) {
915 clicked_regionview = 0;
918 if (entered_regionview == rv) {
919 set_entered_regionview (0);
922 if (!_all_region_actions_sensitized) {
923 sensitize_all_region_actions (true);
928 Editor::set_entered_regionview (RegionView* rv)
930 if (rv == entered_regionview) {
934 if (entered_regionview) {
935 entered_regionview->exited ();
938 entered_regionview = rv;
940 if (entered_regionview != 0) {
941 entered_regionview->entered ();
944 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
945 /* This RegionView entry might have changed what region actions
946 are allowed, so sensitize them all in case a key is pressed.
948 sensitize_all_region_actions (true);
953 Editor::set_entered_track (TimeAxisView* tav)
956 entered_track->exited ();
962 entered_track->entered ();
967 Editor::instant_save ()
969 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
974 _session->add_instant_xml(get_state());
976 Config->add_instant_xml(get_state());
981 Editor::control_vertical_zoom_in_all ()
983 tav_zoom_smooth (false, true);
987 Editor::control_vertical_zoom_out_all ()
989 tav_zoom_smooth (true, true);
993 Editor::control_vertical_zoom_in_selected ()
995 tav_zoom_smooth (false, false);
999 Editor::control_vertical_zoom_out_selected ()
1001 tav_zoom_smooth (true, false);
1005 Editor::control_view (uint32_t view)
1007 goto_visual_state (view);
1011 Editor::control_unselect ()
1013 selection->clear_tracks ();
1017 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1019 TimeAxisView* tav = axis_view_from_stripable (s);
1023 case Selection::Add:
1024 selection->add (tav);
1026 case Selection::Toggle:
1027 selection->toggle (tav);
1029 case Selection::Extend:
1031 case Selection::Set:
1032 selection->set (tav);
1036 selection->clear_tracks ();
1041 Editor::control_step_tracks_up ()
1043 scroll_tracks_up_line ();
1047 Editor::control_step_tracks_down ()
1049 scroll_tracks_down_line ();
1053 Editor::control_scroll (float fraction)
1055 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1061 double step = fraction * current_page_samples();
1064 _control_scroll_target is an optional<T>
1066 it acts like a pointer to an framepos_t, with
1067 a operator conversion to boolean to check
1068 that it has a value could possibly use
1069 playhead_cursor->current_frame to store the
1070 value and a boolean in the class to know
1071 when it's out of date
1074 if (!_control_scroll_target) {
1075 _control_scroll_target = _session->transport_frame();
1076 _dragging_playhead = true;
1079 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1080 *_control_scroll_target = 0;
1081 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1082 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1084 *_control_scroll_target += (framepos_t) trunc (step);
1087 /* move visuals, we'll catch up with it later */
1089 playhead_cursor->set_position (*_control_scroll_target);
1090 UpdateAllTransportClocks (*_control_scroll_target);
1092 if (*_control_scroll_target > (current_page_samples() / 2)) {
1093 /* try to center PH in window */
1094 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1100 Now we do a timeout to actually bring the session to the right place
1101 according to the playhead. This is to avoid reading disk buffers on every
1102 call to control_scroll, which is driven by ScrollTimeline and therefore
1103 probably by a control surface wheel which can generate lots of events.
1105 /* cancel the existing timeout */
1107 control_scroll_connection.disconnect ();
1109 /* add the next timeout */
1111 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1115 Editor::deferred_control_scroll (framepos_t /*target*/)
1117 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1118 // reset for next stream
1119 _control_scroll_target = boost::none;
1120 _dragging_playhead = false;
1125 Editor::access_action (std::string action_group, std::string action_item)
1131 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1134 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1142 Editor::on_realize ()
1146 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1147 start_lock_event_timing ();
1152 Editor::start_lock_event_timing ()
1154 /* check if we should lock the GUI every 30 seconds */
1156 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1160 Editor::generic_event_handler (GdkEvent* ev)
1163 case GDK_BUTTON_PRESS:
1164 case GDK_BUTTON_RELEASE:
1165 case GDK_MOTION_NOTIFY:
1167 case GDK_KEY_RELEASE:
1168 if (contents().is_mapped()) {
1169 gettimeofday (&last_event_time, 0);
1173 case GDK_LEAVE_NOTIFY:
1174 switch (ev->crossing.detail) {
1175 case GDK_NOTIFY_UNKNOWN:
1176 case GDK_NOTIFY_INFERIOR:
1177 case GDK_NOTIFY_ANCESTOR:
1179 case GDK_NOTIFY_VIRTUAL:
1180 case GDK_NOTIFY_NONLINEAR:
1181 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1182 /* leaving window, so reset focus, thus ending any and
1183 all text entry operations.
1185 reset_focus (&contents());
1198 Editor::lock_timeout_callback ()
1200 struct timeval now, delta;
1202 gettimeofday (&now, 0);
1204 timersub (&now, &last_event_time, &delta);
1206 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1208 /* don't call again. Returning false will effectively
1209 disconnect us from the timer callback.
1211 unlock() will call start_lock_event_timing() to get things
1221 Editor::map_position_change (framepos_t frame)
1223 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1225 if (_session == 0) {
1229 if (_follow_playhead) {
1230 center_screen (frame);
1233 playhead_cursor->set_position (frame);
1237 Editor::center_screen (framepos_t frame)
1239 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1241 /* if we're off the page, then scroll.
1244 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1245 center_screen_internal (frame, page);
1250 Editor::center_screen_internal (framepos_t frame, float page)
1255 frame -= (framepos_t) page;
1260 reset_x_origin (frame);
1265 Editor::update_title ()
1267 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1269 if (!own_window()) {
1274 bool dirty = _session->dirty();
1276 string session_name;
1278 if (_session->snap_name() != _session->name()) {
1279 session_name = _session->snap_name();
1281 session_name = _session->name();
1285 session_name = "*" + session_name;
1288 WindowTitle title(session_name);
1289 title += S_("Window|Editor");
1290 title += Glib::get_application_name();
1291 own_window()->set_title (title.get_string());
1293 /* ::session_going_away() will have taken care of it */
1298 Editor::set_session (Session *t)
1300 SessionHandlePtr::set_session (t);
1306 _playlist_selector->set_session (_session);
1307 nudge_clock->set_session (_session);
1308 _summary->set_session (_session);
1309 _group_tabs->set_session (_session);
1310 _route_groups->set_session (_session);
1311 _regions->set_session (_session);
1312 _snapshots->set_session (_session);
1313 _routes->set_session (_session);
1314 _locations->set_session (_session);
1316 if (rhythm_ferret) {
1317 rhythm_ferret->set_session (_session);
1320 if (analysis_window) {
1321 analysis_window->set_session (_session);
1325 sfbrowser->set_session (_session);
1328 compute_fixed_ruler_scale ();
1330 /* Make sure we have auto loop and auto punch ranges */
1332 Location* loc = _session->locations()->auto_loop_location();
1334 loc->set_name (_("Loop"));
1337 loc = _session->locations()->auto_punch_location();
1340 loc->set_name (_("Punch"));
1343 refresh_location_display ();
1345 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1346 the selected Marker; this needs the LocationMarker list to be available.
1348 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1349 set_state (*node, Stateful::loading_state_version);
1351 /* catch up with the playhead */
1353 _session->request_locate (playhead_cursor->current_frame ());
1354 _pending_initial_locate = true;
1358 /* These signals can all be emitted by a non-GUI thread. Therefore the
1359 handlers for them must not attempt to directly interact with the GUI,
1360 but use PBD::Signal<T>::connect() which accepts an event loop
1361 ("context") where the handler will be asked to run.
1364 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1365 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1366 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1367 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1368 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1369 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1370 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1371 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::marker_position_changed, this), gui_context());
1372 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1373 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1374 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1375 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1376 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1377 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1378 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1380 playhead_cursor->show ();
1382 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1383 Config->map_parameters (pc);
1384 _session->config.map_parameters (pc);
1386 restore_ruler_visibility ();
1387 //tempo_map_changed (PropertyChange (0));
1388 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1390 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1391 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1394 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1395 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1398 switch (_snap_type) {
1399 case SnapToRegionStart:
1400 case SnapToRegionEnd:
1401 case SnapToRegionSync:
1402 case SnapToRegionBoundary:
1403 build_region_boundary_cache ();
1410 /* catch up on selection of stripables (other selection state is lost
1411 * when a session is closed
1416 _session->get_stripables (sl);
1417 for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
1418 if ((*s)->presentation_info().selected()) {
1419 RouteTimeAxisView* rtav = get_route_view_by_route_id ((*s)->id());
1421 tl.push_back (rtav);
1426 selection->set (tl);
1429 /* register for undo history */
1430 _session->register_with_memento_command_factory(id(), this);
1431 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1433 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1435 LuaInstance::instance()->set_session(_session);
1437 start_updating_meters ();
1441 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1443 if (a->get_name() == "RegionMenu") {
1444 /* When the main menu's region menu is opened, we setup the actions so that they look right
1445 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1446 so we resensitize all region actions when the entered regionview or the region selection
1447 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1448 happens after the region context menu is opened. So we set a flag here, too.
1452 sensitize_the_right_region_actions ();
1453 _last_region_menu_was_main = true;
1458 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1460 using namespace Menu_Helpers;
1462 void (Editor::*emf)(FadeShape);
1463 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1466 images = &_xfade_in_images;
1467 emf = &Editor::set_fade_in_shape;
1469 images = &_xfade_out_images;
1470 emf = &Editor::set_fade_out_shape;
1475 _("Linear (for highly correlated material)"),
1476 *(*images)[FadeLinear],
1477 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1481 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1485 _("Constant power"),
1486 *(*images)[FadeConstantPower],
1487 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1490 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1495 *(*images)[FadeSymmetric],
1496 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1500 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1505 *(*images)[FadeSlow],
1506 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1509 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1514 *(*images)[FadeFast],
1515 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1518 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1521 /** Pop up a context menu for when the user clicks on a start crossfade */
1523 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1525 using namespace Menu_Helpers;
1526 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1531 MenuList& items (xfade_in_context_menu.items());
1534 if (arv->audio_region()->fade_in_active()) {
1535 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1537 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1540 items.push_back (SeparatorElem());
1541 fill_xfade_menu (items, true);
1543 xfade_in_context_menu.popup (button, time);
1546 /** Pop up a context menu for when the user clicks on an end crossfade */
1548 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1550 using namespace Menu_Helpers;
1551 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1556 MenuList& items (xfade_out_context_menu.items());
1559 if (arv->audio_region()->fade_out_active()) {
1560 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1562 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1565 items.push_back (SeparatorElem());
1566 fill_xfade_menu (items, false);
1568 xfade_out_context_menu.popup (button, time);
1572 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1574 using namespace Menu_Helpers;
1575 Menu* (Editor::*build_menu_function)();
1578 switch (item_type) {
1580 case RegionViewName:
1581 case RegionViewNameHighlight:
1582 case LeftFrameHandle:
1583 case RightFrameHandle:
1584 if (with_selection) {
1585 build_menu_function = &Editor::build_track_selection_context_menu;
1587 build_menu_function = &Editor::build_track_region_context_menu;
1592 if (with_selection) {
1593 build_menu_function = &Editor::build_track_selection_context_menu;
1595 build_menu_function = &Editor::build_track_context_menu;
1600 if (clicked_routeview->track()) {
1601 build_menu_function = &Editor::build_track_context_menu;
1603 build_menu_function = &Editor::build_track_bus_context_menu;
1608 /* probably shouldn't happen but if it does, we don't care */
1612 menu = (this->*build_menu_function)();
1613 menu->set_name ("ArdourContextMenu");
1615 /* now handle specific situations */
1617 switch (item_type) {
1619 case RegionViewName:
1620 case RegionViewNameHighlight:
1621 case LeftFrameHandle:
1622 case RightFrameHandle:
1623 if (!with_selection) {
1624 if (region_edit_menu_split_item) {
1625 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1626 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1628 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1631 if (region_edit_menu_split_multichannel_item) {
1632 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1633 region_edit_menu_split_multichannel_item->set_sensitive (true);
1635 region_edit_menu_split_multichannel_item->set_sensitive (false);
1648 /* probably shouldn't happen but if it does, we don't care */
1652 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1654 /* Bounce to disk */
1656 using namespace Menu_Helpers;
1657 MenuList& edit_items = menu->items();
1659 edit_items.push_back (SeparatorElem());
1661 switch (clicked_routeview->audio_track()->freeze_state()) {
1662 case AudioTrack::NoFreeze:
1663 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1666 case AudioTrack::Frozen:
1667 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1670 case AudioTrack::UnFrozen:
1671 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1677 if (item_type == StreamItem && clicked_routeview) {
1678 clicked_routeview->build_underlay_menu(menu);
1681 /* When the region menu is opened, we setup the actions so that they look right
1684 sensitize_the_right_region_actions ();
1685 _last_region_menu_was_main = false;
1687 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1688 menu->popup (button, time);
1692 Editor::build_track_context_menu ()
1694 using namespace Menu_Helpers;
1696 MenuList& edit_items = track_context_menu.items();
1699 add_dstream_context_items (edit_items);
1700 return &track_context_menu;
1704 Editor::build_track_bus_context_menu ()
1706 using namespace Menu_Helpers;
1708 MenuList& edit_items = track_context_menu.items();
1711 add_bus_context_items (edit_items);
1712 return &track_context_menu;
1716 Editor::build_track_region_context_menu ()
1718 using namespace Menu_Helpers;
1719 MenuList& edit_items = track_region_context_menu.items();
1722 /* we've just cleared the track region context menu, so the menu that these
1723 two items were on will have disappeared; stop them dangling.
1725 region_edit_menu_split_item = 0;
1726 region_edit_menu_split_multichannel_item = 0;
1728 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1731 boost::shared_ptr<Track> tr;
1732 boost::shared_ptr<Playlist> pl;
1734 if ((tr = rtv->track())) {
1735 add_region_context_items (edit_items, tr);
1739 add_dstream_context_items (edit_items);
1741 return &track_region_context_menu;
1745 Editor::loudness_analyze_region_selection ()
1750 Selection& s (PublicEditor::instance ().get_selection ());
1751 RegionSelection ars = s.regions;
1752 ARDOUR::AnalysisGraph ag (_session);
1753 framecnt_t total_work = 0;
1755 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1756 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1760 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1763 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1764 total_work += arv->region ()->length ();
1767 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1769 ag.set_total_frames (total_work);
1770 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1773 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1774 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1778 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1782 ag.analyze_region (ar);
1785 if (!ag.canceled ()) {
1786 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1792 Editor::loudness_analyze_range_selection ()
1797 Selection& s (PublicEditor::instance ().get_selection ());
1798 TimeSelection ts = s.time;
1799 ARDOUR::AnalysisGraph ag (_session);
1800 framecnt_t total_work = 0;
1802 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1803 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1807 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1811 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1812 total_work += j->length ();
1816 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1818 ag.set_total_frames (total_work);
1819 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1822 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1823 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1827 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1831 ag.analyze_range (rui->route (), pl, ts);
1834 if (!ag.canceled ()) {
1835 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1841 Editor::spectral_analyze_region_selection ()
1843 if (analysis_window == 0) {
1844 analysis_window = new AnalysisWindow();
1847 analysis_window->set_session(_session);
1849 analysis_window->show_all();
1852 analysis_window->set_regionmode();
1853 analysis_window->analyze();
1855 analysis_window->present();
1859 Editor::spectral_analyze_range_selection()
1861 if (analysis_window == 0) {
1862 analysis_window = new AnalysisWindow();
1865 analysis_window->set_session(_session);
1867 analysis_window->show_all();
1870 analysis_window->set_rangemode();
1871 analysis_window->analyze();
1873 analysis_window->present();
1877 Editor::build_track_selection_context_menu ()
1879 using namespace Menu_Helpers;
1880 MenuList& edit_items = track_selection_context_menu.items();
1881 edit_items.clear ();
1883 add_selection_context_items (edit_items);
1884 // edit_items.push_back (SeparatorElem());
1885 // add_dstream_context_items (edit_items);
1887 return &track_selection_context_menu;
1891 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1893 using namespace Menu_Helpers;
1895 /* OK, stick the region submenu at the top of the list, and then add
1899 RegionSelection rs = get_regions_from_selection_and_entered ();
1901 string::size_type pos = 0;
1902 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1904 /* we have to hack up the region name because "_" has a special
1905 meaning for menu titles.
1908 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1909 menu_item_name.replace (pos, 1, "__");
1913 if (_popup_region_menu_item == 0) {
1914 _popup_region_menu_item = new MenuItem (menu_item_name);
1915 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1916 _popup_region_menu_item->show ();
1918 _popup_region_menu_item->set_label (menu_item_name);
1921 /* No latering allowed in later is higher layering model */
1922 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1923 if (act && Config->get_layer_model() == LaterHigher) {
1924 act->set_sensitive (false);
1926 act->set_sensitive (true);
1929 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1931 edit_items.push_back (*_popup_region_menu_item);
1932 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1933 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1935 edit_items.push_back (SeparatorElem());
1938 /** Add context menu items relevant to selection ranges.
1939 * @param edit_items List to add the items to.
1942 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1944 using namespace Menu_Helpers;
1946 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1947 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1949 edit_items.push_back (SeparatorElem());
1950 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1952 edit_items.push_back (SeparatorElem());
1953 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1954 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1956 edit_items.push_back (SeparatorElem());
1958 edit_items.push_back (
1960 _("Move Range Start to Previous Region Boundary"),
1961 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1965 edit_items.push_back (
1967 _("Move Range Start to Next Region Boundary"),
1968 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1972 edit_items.push_back (
1974 _("Move Range End to Previous Region Boundary"),
1975 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1979 edit_items.push_back (
1981 _("Move Range End to Next Region Boundary"),
1982 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1986 edit_items.push_back (SeparatorElem());
1987 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1988 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1990 edit_items.push_back (SeparatorElem());
1991 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1993 edit_items.push_back (SeparatorElem());
1994 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1995 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1996 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1998 edit_items.push_back (SeparatorElem());
1999 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
2001 edit_items.push_back (SeparatorElem());
2002 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
2003 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
2005 edit_items.push_back (SeparatorElem());
2006 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
2007 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
2008 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
2009 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
2010 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
2011 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
2012 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2018 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2020 using namespace Menu_Helpers;
2024 Menu *play_menu = manage (new Menu);
2025 MenuList& play_items = play_menu->items();
2026 play_menu->set_name ("ArdourContextMenu");
2028 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2029 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2030 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2031 play_items.push_back (SeparatorElem());
2032 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2034 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2038 Menu *select_menu = manage (new Menu);
2039 MenuList& select_items = select_menu->items();
2040 select_menu->set_name ("ArdourContextMenu");
2042 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2043 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2044 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2045 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2046 select_items.push_back (SeparatorElem());
2047 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2048 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2049 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2050 select_items.push_back (SeparatorElem());
2051 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2052 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2053 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2054 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2055 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2056 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2057 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2059 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2063 Menu *cutnpaste_menu = manage (new Menu);
2064 MenuList& cutnpaste_items = cutnpaste_menu->items();
2065 cutnpaste_menu->set_name ("ArdourContextMenu");
2067 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2068 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2069 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2071 cutnpaste_items.push_back (SeparatorElem());
2073 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2074 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2076 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2078 /* Adding new material */
2080 edit_items.push_back (SeparatorElem());
2081 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2082 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2086 Menu *nudge_menu = manage (new Menu());
2087 MenuList& nudge_items = nudge_menu->items();
2088 nudge_menu->set_name ("ArdourContextMenu");
2090 edit_items.push_back (SeparatorElem());
2091 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2092 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2093 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2094 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2096 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2100 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2102 using namespace Menu_Helpers;
2106 Menu *play_menu = manage (new Menu);
2107 MenuList& play_items = play_menu->items();
2108 play_menu->set_name ("ArdourContextMenu");
2110 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2111 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2112 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2116 Menu *select_menu = manage (new Menu);
2117 MenuList& select_items = select_menu->items();
2118 select_menu->set_name ("ArdourContextMenu");
2120 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2121 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2122 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2123 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2124 select_items.push_back (SeparatorElem());
2125 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2126 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2127 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2128 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2130 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2134 Menu *cutnpaste_menu = manage (new Menu);
2135 MenuList& cutnpaste_items = cutnpaste_menu->items();
2136 cutnpaste_menu->set_name ("ArdourContextMenu");
2138 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2139 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2140 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2142 Menu *nudge_menu = manage (new Menu());
2143 MenuList& nudge_items = nudge_menu->items();
2144 nudge_menu->set_name ("ArdourContextMenu");
2146 edit_items.push_back (SeparatorElem());
2147 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2148 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2149 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2150 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2152 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2156 Editor::snap_type() const
2162 Editor::snap_musical() const
2164 switch (_snap_type) {
2165 case SnapToBeatDiv128:
2166 case SnapToBeatDiv64:
2167 case SnapToBeatDiv32:
2168 case SnapToBeatDiv28:
2169 case SnapToBeatDiv24:
2170 case SnapToBeatDiv20:
2171 case SnapToBeatDiv16:
2172 case SnapToBeatDiv14:
2173 case SnapToBeatDiv12:
2174 case SnapToBeatDiv10:
2175 case SnapToBeatDiv8:
2176 case SnapToBeatDiv7:
2177 case SnapToBeatDiv6:
2178 case SnapToBeatDiv5:
2179 case SnapToBeatDiv4:
2180 case SnapToBeatDiv3:
2181 case SnapToBeatDiv2:
2193 Editor::snap_mode() const
2199 Editor::set_snap_to (SnapType st)
2201 unsigned int snap_ind = (unsigned int)st;
2203 if (internal_editing()) {
2204 internal_snap_type = st;
2206 pre_internal_snap_type = st;
2211 if (snap_ind > snap_type_strings.size() - 1) {
2213 _snap_type = (SnapType)snap_ind;
2216 string str = snap_type_strings[snap_ind];
2218 if (str != snap_type_selector.get_text()) {
2219 snap_type_selector.set_text (str);
2224 switch (_snap_type) {
2225 case SnapToBeatDiv128:
2226 case SnapToBeatDiv64:
2227 case SnapToBeatDiv32:
2228 case SnapToBeatDiv28:
2229 case SnapToBeatDiv24:
2230 case SnapToBeatDiv20:
2231 case SnapToBeatDiv16:
2232 case SnapToBeatDiv14:
2233 case SnapToBeatDiv12:
2234 case SnapToBeatDiv10:
2235 case SnapToBeatDiv8:
2236 case SnapToBeatDiv7:
2237 case SnapToBeatDiv6:
2238 case SnapToBeatDiv5:
2239 case SnapToBeatDiv4:
2240 case SnapToBeatDiv3:
2241 case SnapToBeatDiv2: {
2242 std::vector<TempoMap::BBTPoint> grid;
2243 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
2244 compute_bbt_ruler_scale (grid, leftmost_frame, leftmost_frame + current_page_samples());
2245 update_tempo_based_rulers (grid);
2249 case SnapToRegionStart:
2250 case SnapToRegionEnd:
2251 case SnapToRegionSync:
2252 case SnapToRegionBoundary:
2253 build_region_boundary_cache ();
2261 redisplay_tempo (false);
2263 SnapChanged (); /* EMIT SIGNAL */
2267 Editor::set_snap_mode (SnapMode mode)
2269 string str = snap_mode_strings[(int)mode];
2271 if (internal_editing()) {
2272 internal_snap_mode = mode;
2274 pre_internal_snap_mode = mode;
2279 if (str != snap_mode_selector.get_text ()) {
2280 snap_mode_selector.set_text (str);
2287 Editor::set_edit_point_preference (EditPoint ep, bool force)
2289 bool changed = (_edit_point != ep);
2292 if (Profile->get_mixbus())
2293 if (ep == EditAtSelectedMarker)
2294 ep = EditAtPlayhead;
2296 string str = edit_point_strings[(int)ep];
2297 if (str != edit_point_selector.get_text ()) {
2298 edit_point_selector.set_text (str);
2301 update_all_enter_cursors();
2303 if (!force && !changed) {
2307 const char* action=NULL;
2309 switch (_edit_point) {
2310 case EditAtPlayhead:
2311 action = "edit-at-playhead";
2313 case EditAtSelectedMarker:
2314 action = "edit-at-marker";
2317 action = "edit-at-mouse";
2321 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2323 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2327 bool in_track_canvas;
2329 if (!mouse_frame (foo, in_track_canvas)) {
2330 in_track_canvas = false;
2333 reset_canvas_action_sensitivity (in_track_canvas);
2339 Editor::set_state (const XMLNode& node, int version)
2341 XMLProperty const * prop;
2343 PBD::Unwinder<bool> nsi (no_save_instant, true);
2346 Tabbable::set_state (node, version);
2348 if (_session && (prop = node.property ("playhead"))) {
2350 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2352 playhead_cursor->set_position (pos);
2354 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2355 playhead_cursor->set_position (0);
2358 playhead_cursor->set_position (0);
2361 if ((prop = node.property ("mixer-width"))) {
2362 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2365 if ((prop = node.property ("zoom-focus"))) {
2366 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2368 zoom_focus_selection_done (zoom_focus);
2371 if ((prop = node.property ("zoom"))) {
2372 /* older versions of ardour used floating point samples_per_pixel */
2373 double f = PBD::atof (prop->value());
2374 reset_zoom (llrintf (f));
2376 reset_zoom (samples_per_pixel);
2379 if ((prop = node.property ("visible-track-count"))) {
2380 set_visible_track_count (PBD::atoi (prop->value()));
2383 if ((prop = node.property ("snap-to"))) {
2384 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2385 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2387 set_snap_to (_snap_type);
2390 if ((prop = node.property ("snap-mode"))) {
2391 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2392 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2393 * snap_mode_selection_done() will only mark an already active item as active
2394 * which does not trigger set_text().
2396 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2398 set_snap_mode (_snap_mode);
2401 if ((prop = node.property ("internal-snap-to"))) {
2402 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2405 if ((prop = node.property ("internal-snap-mode"))) {
2406 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2409 if ((prop = node.property ("pre-internal-snap-to"))) {
2410 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2413 if ((prop = node.property ("pre-internal-snap-mode"))) {
2414 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2417 if ((prop = node.property ("mouse-mode"))) {
2418 MouseMode m = str2mousemode(prop->value());
2419 set_mouse_mode (m, true);
2421 set_mouse_mode (MouseObject, true);
2424 if ((prop = node.property ("left-frame")) != 0) {
2426 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2430 reset_x_origin (pos);
2434 if ((prop = node.property ("y-origin")) != 0) {
2435 reset_y_origin (atof (prop->value ()));
2438 if ((prop = node.property ("join-object-range"))) {
2439 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2440 bool yn = string_is_affirmative (prop->value());
2442 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2443 tact->set_active (!yn);
2444 tact->set_active (yn);
2446 set_mouse_mode(mouse_mode, true);
2449 if ((prop = node.property ("edit-point"))) {
2450 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2452 set_edit_point_preference (_edit_point);
2455 if ((prop = node.property ("show-measures"))) {
2456 bool yn = string_is_affirmative (prop->value());
2457 _show_measures = yn;
2460 if ((prop = node.property ("follow-playhead"))) {
2461 bool yn = string_is_affirmative (prop->value());
2462 set_follow_playhead (yn);
2465 if ((prop = node.property ("stationary-playhead"))) {
2466 bool yn = string_is_affirmative (prop->value());
2467 set_stationary_playhead (yn);
2470 if ((prop = node.property ("region-list-sort-type"))) {
2471 RegionListSortType st;
2472 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2475 if ((prop = node.property ("show-editor-mixer"))) {
2477 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2480 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2481 bool yn = string_is_affirmative (prop->value());
2483 /* do it twice to force the change */
2485 tact->set_active (!yn);
2486 tact->set_active (yn);
2489 if ((prop = node.property ("show-editor-list"))) {
2491 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2494 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2495 bool yn = string_is_affirmative (prop->value());
2497 /* do it twice to force the change */
2499 tact->set_active (!yn);
2500 tact->set_active (yn);
2503 if ((prop = node.property (X_("editor-list-page")))) {
2504 _the_notebook.set_current_page (atoi (prop->value ()));
2507 if ((prop = node.property (X_("show-marker-lines")))) {
2508 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2510 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2511 bool yn = string_is_affirmative (prop->value ());
2513 tact->set_active (!yn);
2514 tact->set_active (yn);
2517 XMLNodeList children = node.children ();
2518 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2519 selection->set_state (**i, Stateful::current_state_version);
2520 _regions->set_state (**i);
2523 if ((prop = node.property ("maximised"))) {
2524 bool yn = string_is_affirmative (prop->value());
2525 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2527 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2528 bool fs = tact && tact->get_active();
2530 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2534 if ((prop = node.property ("nudge-clock-value"))) {
2536 sscanf (prop->value().c_str(), "%" PRId64, &f);
2537 nudge_clock->set (f);
2539 nudge_clock->set_mode (AudioClock::Timecode);
2540 nudge_clock->set (_session->frame_rate() * 5, true);
2545 * Not all properties may have been in XML, but
2546 * those that are linked to a private variable may need changing
2551 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2553 yn = _show_measures;
2554 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2555 /* do it twice to force the change */
2556 tact->set_active (!yn);
2557 tact->set_active (yn);
2560 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2561 yn = _follow_playhead;
2563 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2564 if (tact->get_active() != yn) {
2565 tact->set_active (yn);
2569 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2570 yn = _stationary_playhead;
2572 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2573 if (tact->get_active() != yn) {
2574 tact->set_active (yn);
2579 return LuaInstance::instance()->set_state(node);
2583 Editor::get_state ()
2585 XMLNode* node = new XMLNode (X_("Editor"));
2589 id().print (buf, sizeof (buf));
2590 node->add_property ("id", buf);
2592 node->add_child_nocopy (Tabbable::get_state());
2594 snprintf(buf,sizeof(buf), "%f", edit_pane.get_divider ());
2595 node->add_property("edit-horizontal-pane-pos", string(buf));
2596 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2597 snprintf(buf,sizeof(buf), "%f", editor_summary_pane.get_divider());
2598 node->add_property("edit-vertical-pane-pos", string(buf));
2600 maybe_add_mixer_strip_width (*node);
2602 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2604 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2605 node->add_property ("zoom", buf);
2606 node->add_property ("snap-to", enum_2_string (_snap_type));
2607 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2608 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2609 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2610 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2611 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2612 node->add_property ("edit-point", enum_2_string (_edit_point));
2613 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2614 node->add_property ("visible-track-count", buf);
2616 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2617 node->add_property ("playhead", buf);
2618 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2619 node->add_property ("left-frame", buf);
2620 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2621 node->add_property ("y-origin", buf);
2623 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2624 node->add_property ("maximised", _maximised ? "yes" : "no");
2625 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2626 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2627 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2628 node->add_property ("mouse-mode", enum2str(mouse_mode));
2629 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2631 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2633 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2634 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2637 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2639 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2640 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2643 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2644 node->add_property (X_("editor-list-page"), buf);
2646 if (button_bindings) {
2647 XMLNode* bb = new XMLNode (X_("Buttons"));
2648 button_bindings->save (*bb);
2649 node->add_child_nocopy (*bb);
2652 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2654 node->add_child_nocopy (selection->get_state ());
2655 node->add_child_nocopy (_regions->get_state ());
2657 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2658 node->add_property ("nudge-clock-value", buf);
2660 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2661 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2666 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2667 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2669 * @return pair: TimeAxisView that y is over, layer index.
2671 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2672 * in stacked or expanded region display mode, otherwise 0.
2674 std::pair<TimeAxisView *, double>
2675 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2677 if (!trackview_relative_offset) {
2678 y -= _trackview_group->canvas_origin().y;
2682 return std::make_pair ( (TimeAxisView *) 0, 0);
2685 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2687 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2694 return std::make_pair ( (TimeAxisView *) 0, 0);
2697 /** Snap a position to the grid, if appropriate, taking into account current
2698 * grid settings and also the state of any snap modifier keys that may be pressed.
2699 * @param start Position to snap.
2700 * @param event Event to get current key modifier information from, or 0.
2703 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2705 if (!_session || !event) {
2709 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2710 if (_snap_mode == SnapOff) {
2711 snap_to_internal (start, direction, for_mark);
2714 if (_snap_mode != SnapOff) {
2715 snap_to_internal (start, direction, for_mark);
2716 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2717 /* SnapOff, but we pressed the snap_delta modifier */
2718 snap_to_internal (start, direction, for_mark);
2724 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2726 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2730 snap_to_internal (start, direction, for_mark, ensure_snap);
2734 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2736 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2737 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2739 switch (_snap_type) {
2740 case SnapToTimecodeFrame:
2741 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2742 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2743 /* start is already on a whole timecode frame, do nothing */
2744 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2745 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2747 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2751 case SnapToTimecodeSeconds:
2752 if (_session->config.get_timecode_offset_negative()) {
2753 start += _session->config.get_timecode_offset ();
2755 start -= _session->config.get_timecode_offset ();
2757 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2758 (start % one_timecode_second == 0)) {
2759 /* start is already on a whole second, do nothing */
2760 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2761 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2763 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2766 if (_session->config.get_timecode_offset_negative()) {
2767 start -= _session->config.get_timecode_offset ();
2769 start += _session->config.get_timecode_offset ();
2773 case SnapToTimecodeMinutes:
2774 if (_session->config.get_timecode_offset_negative()) {
2775 start += _session->config.get_timecode_offset ();
2777 start -= _session->config.get_timecode_offset ();
2779 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2780 (start % one_timecode_minute == 0)) {
2781 /* start is already on a whole minute, do nothing */
2782 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2783 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2785 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2787 if (_session->config.get_timecode_offset_negative()) {
2788 start -= _session->config.get_timecode_offset ();
2790 start += _session->config.get_timecode_offset ();
2794 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2795 abort(); /*NOTREACHED*/
2800 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2802 const framepos_t one_second = _session->frame_rate();
2803 const framepos_t one_minute = _session->frame_rate() * 60;
2804 framepos_t presnap = start;
2808 switch (_snap_type) {
2809 case SnapToTimecodeFrame:
2810 case SnapToTimecodeSeconds:
2811 case SnapToTimecodeMinutes:
2812 return timecode_snap_to_internal (start, direction, for_mark);
2815 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2816 start % (one_second/75) == 0) {
2817 /* start is already on a whole CD frame, do nothing */
2818 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2819 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2821 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2826 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2827 start % one_second == 0) {
2828 /* start is already on a whole second, do nothing */
2829 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2830 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2832 start = (framepos_t) floor ((double) start / one_second) * one_second;
2837 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2838 start % one_minute == 0) {
2839 /* start is already on a whole minute, do nothing */
2840 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2841 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2843 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2848 start = _session->tempo_map().round_to_bar (start, direction);
2852 start = _session->tempo_map().round_to_beat (start, direction);
2855 case SnapToBeatDiv128:
2856 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2858 case SnapToBeatDiv64:
2859 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2861 case SnapToBeatDiv32:
2862 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2864 case SnapToBeatDiv28:
2865 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2867 case SnapToBeatDiv24:
2868 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2870 case SnapToBeatDiv20:
2871 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2873 case SnapToBeatDiv16:
2874 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2876 case SnapToBeatDiv14:
2877 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2879 case SnapToBeatDiv12:
2880 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2882 case SnapToBeatDiv10:
2883 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2885 case SnapToBeatDiv8:
2886 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2888 case SnapToBeatDiv7:
2889 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2891 case SnapToBeatDiv6:
2892 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2894 case SnapToBeatDiv5:
2895 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2897 case SnapToBeatDiv4:
2898 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2900 case SnapToBeatDiv3:
2901 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2903 case SnapToBeatDiv2:
2904 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2912 _session->locations()->marks_either_side (start, before, after);
2914 if (before == max_framepos && after == max_framepos) {
2915 /* No marks to snap to, so just don't snap */
2917 } else if (before == max_framepos) {
2919 } else if (after == max_framepos) {
2921 } else if (before != max_framepos && after != max_framepos) {
2922 /* have before and after */
2923 if ((start - before) < (after - start)) {
2932 case SnapToRegionStart:
2933 case SnapToRegionEnd:
2934 case SnapToRegionSync:
2935 case SnapToRegionBoundary:
2936 if (!region_boundary_cache.empty()) {
2938 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2939 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2941 if (direction > 0) {
2942 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2944 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2947 if (next != region_boundary_cache.begin ()) {
2952 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2953 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2955 if (start > (p + n) / 2) {
2964 switch (_snap_mode) {
2974 if (presnap > start) {
2975 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2979 } else if (presnap < start) {
2980 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2986 /* handled at entry */
2994 Editor::setup_toolbar ()
2996 HBox* mode_box = manage(new HBox);
2997 mode_box->set_border_width (2);
2998 mode_box->set_spacing(2);
3000 HBox* mouse_mode_box = manage (new HBox);
3001 HBox* mouse_mode_hbox = manage (new HBox);
3002 VBox* mouse_mode_vbox = manage (new VBox);
3003 Alignment* mouse_mode_align = manage (new Alignment);
3005 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3006 mouse_mode_size_group->add_widget (smart_mode_button);
3007 mouse_mode_size_group->add_widget (mouse_move_button);
3008 mouse_mode_size_group->add_widget (mouse_cut_button);
3009 mouse_mode_size_group->add_widget (mouse_select_button);
3010 mouse_mode_size_group->add_widget (mouse_timefx_button);
3011 mouse_mode_size_group->add_widget (mouse_audition_button);
3012 mouse_mode_size_group->add_widget (mouse_draw_button);
3013 mouse_mode_size_group->add_widget (mouse_content_button);
3015 mouse_mode_size_group->add_widget (zoom_in_button);
3016 mouse_mode_size_group->add_widget (zoom_out_button);
3017 mouse_mode_size_group->add_widget (zoom_preset_selector);
3018 mouse_mode_size_group->add_widget (zoom_out_full_button);
3019 mouse_mode_size_group->add_widget (zoom_focus_selector);
3021 mouse_mode_size_group->add_widget (tav_shrink_button);
3022 mouse_mode_size_group->add_widget (tav_expand_button);
3023 mouse_mode_size_group->add_widget (visible_tracks_selector);
3025 mouse_mode_size_group->add_widget (snap_type_selector);
3026 mouse_mode_size_group->add_widget (snap_mode_selector);
3028 mouse_mode_size_group->add_widget (edit_point_selector);
3029 mouse_mode_size_group->add_widget (edit_mode_selector);
3031 mouse_mode_size_group->add_widget (*nudge_clock);
3032 mouse_mode_size_group->add_widget (nudge_forward_button);
3033 mouse_mode_size_group->add_widget (nudge_backward_button);
3035 mouse_mode_hbox->set_spacing (2);
3037 if (!ARDOUR::Profile->get_trx()) {
3038 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3041 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3042 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3044 if (!ARDOUR::Profile->get_mixbus()) {
3045 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3048 if (!ARDOUR::Profile->get_trx()) {
3049 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3050 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3051 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3052 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3055 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3057 mouse_mode_align->add (*mouse_mode_vbox);
3058 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3060 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3062 edit_mode_selector.set_name ("mouse mode button");
3064 if (!ARDOUR::Profile->get_trx()) {
3065 mode_box->pack_start (edit_mode_selector, false, false);
3068 mode_box->pack_start (*mouse_mode_box, false, false);
3072 _zoom_box.set_spacing (2);
3073 _zoom_box.set_border_width (2);
3077 zoom_preset_selector.set_name ("zoom button");
3078 zoom_preset_selector.set_image(::get_icon ("time_exp"));
3079 zoom_preset_selector.set_size_request (42, -1);
3081 zoom_in_button.set_name ("zoom button");
3082 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3083 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3084 zoom_in_button.set_related_action (act);
3086 zoom_out_button.set_name ("zoom button");
3087 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3088 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3089 zoom_out_button.set_related_action (act);
3091 zoom_out_full_button.set_name ("zoom button");
3092 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3093 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3094 zoom_out_full_button.set_related_action (act);
3096 zoom_focus_selector.set_name ("zoom button");
3098 if (ARDOUR::Profile->get_mixbus()) {
3099 _zoom_box.pack_start (zoom_preset_selector, false, false);
3100 } else if (ARDOUR::Profile->get_trx()) {
3101 mode_box->pack_start (zoom_out_button, false, false);
3102 mode_box->pack_start (zoom_in_button, false, false);
3104 _zoom_box.pack_start (zoom_out_button, false, false);
3105 _zoom_box.pack_start (zoom_in_button, false, false);
3106 _zoom_box.pack_start (zoom_out_full_button, false, false);
3107 _zoom_box.pack_start (zoom_focus_selector, false, false);
3110 /* Track zoom buttons */
3111 visible_tracks_selector.set_name ("zoom button");
3112 if (Profile->get_mixbus()) {
3113 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3114 visible_tracks_selector.set_size_request (42, -1);
3116 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3119 tav_expand_button.set_name ("zoom button");
3120 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3121 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3122 tav_expand_button.set_related_action (act);
3124 tav_shrink_button.set_name ("zoom button");
3125 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3126 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3127 tav_shrink_button.set_related_action (act);
3129 if (ARDOUR::Profile->get_mixbus()) {
3130 _zoom_box.pack_start (visible_tracks_selector);
3131 } else if (ARDOUR::Profile->get_trx()) {
3132 _zoom_box.pack_start (tav_shrink_button);
3133 _zoom_box.pack_start (tav_expand_button);
3135 _zoom_box.pack_start (visible_tracks_selector);
3136 _zoom_box.pack_start (tav_shrink_button);
3137 _zoom_box.pack_start (tav_expand_button);
3140 snap_box.set_spacing (2);
3141 snap_box.set_border_width (2);
3143 snap_type_selector.set_name ("mouse mode button");
3145 snap_mode_selector.set_name ("mouse mode button");
3147 edit_point_selector.set_name ("mouse mode button");
3149 snap_box.pack_start (snap_mode_selector, false, false);
3150 snap_box.pack_start (snap_type_selector, false, false);
3151 snap_box.pack_start (edit_point_selector, false, false);
3155 HBox *nudge_box = manage (new HBox);
3156 nudge_box->set_spacing (2);
3157 nudge_box->set_border_width (2);
3159 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3160 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3162 nudge_box->pack_start (nudge_backward_button, false, false);
3163 nudge_box->pack_start (nudge_forward_button, false, false);
3164 nudge_box->pack_start (*nudge_clock, false, false);
3167 /* Pack everything in... */
3169 HBox* hbox = manage (new HBox);
3170 hbox->set_spacing(2);
3172 toolbar_hbox.set_spacing (2);
3173 toolbar_hbox.set_border_width (1);
3175 toolbar_hbox.pack_start (*mode_box, false, false);
3176 if (!ARDOUR::Profile->get_trx()) {
3177 toolbar_hbox.pack_start (_zoom_box, false, false);
3178 toolbar_hbox.pack_start (*hbox, false, false);
3181 if (!ARDOUR::Profile->get_trx()) {
3182 hbox->pack_start (snap_box, false, false);
3183 hbox->pack_start (*nudge_box, false, false);
3188 toolbar_base.set_name ("ToolBarBase");
3189 toolbar_base.add (toolbar_hbox);
3191 _toolbar_viewport.add (toolbar_base);
3192 /* stick to the required height but allow width to vary if there's not enough room */
3193 _toolbar_viewport.set_size_request (1, -1);
3195 toolbar_frame.set_shadow_type (SHADOW_OUT);
3196 toolbar_frame.set_name ("BaseFrame");
3197 toolbar_frame.add (_toolbar_viewport);
3201 Editor::build_edit_point_menu ()
3203 using namespace Menu_Helpers;
3205 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3206 if(!Profile->get_mixbus())
3207 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3208 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3210 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3214 Editor::build_edit_mode_menu ()
3216 using namespace Menu_Helpers;
3218 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3219 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3220 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3221 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3223 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3227 Editor::build_snap_mode_menu ()
3229 using namespace Menu_Helpers;
3231 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3232 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3233 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3235 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3239 Editor::build_snap_type_menu ()
3241 using namespace Menu_Helpers;
3243 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3244 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3245 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3246 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3247 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3248 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3249 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3250 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3251 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3252 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3253 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3254 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3255 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3256 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3257 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3258 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3259 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3260 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3261 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3262 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3263 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3264 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3265 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3266 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3267 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3268 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3269 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3270 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3271 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3272 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3274 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3279 Editor::setup_tooltips ()
3281 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3282 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3283 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3284 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3285 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3286 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3287 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3288 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3289 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3290 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3291 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3292 set_tooltip (zoom_in_button, _("Zoom In"));
3293 set_tooltip (zoom_out_button, _("Zoom Out"));
3294 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3295 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3296 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3297 set_tooltip (tav_expand_button, _("Expand Tracks"));
3298 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3299 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3300 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3301 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3302 set_tooltip (edit_point_selector, _("Edit Point"));
3303 set_tooltip (edit_mode_selector, _("Edit Mode"));
3304 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3308 Editor::convert_drop_to_paths (
3309 vector<string>& paths,
3310 const RefPtr<Gdk::DragContext>& /*context*/,
3313 const SelectionData& data,
3317 if (_session == 0) {
3321 vector<string> uris = data.get_uris();
3325 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3326 are actually URI lists. So do it by hand.
3329 if (data.get_target() != "text/plain") {
3333 /* Parse the "uri-list" format that Nautilus provides,
3334 where each pathname is delimited by \r\n.
3336 THERE MAY BE NO NULL TERMINATING CHAR!!!
3339 string txt = data.get_text();
3343 p = (char *) malloc (txt.length() + 1);
3344 txt.copy (p, txt.length(), 0);
3345 p[txt.length()] = '\0';
3351 while (g_ascii_isspace (*p))
3355 while (*q && (*q != '\n') && (*q != '\r')) {
3362 while (q > p && g_ascii_isspace (*q))
3367 uris.push_back (string (p, q - p + 1));
3371 p = strchr (p, '\n');
3383 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3384 if ((*i).substr (0,7) == "file://") {
3385 paths.push_back (Glib::filename_from_uri (*i));
3393 Editor::new_tempo_section ()
3398 Editor::map_transport_state ()
3400 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3402 if (_session && _session->transport_stopped()) {
3403 have_pending_keyboard_selection = false;
3406 update_loop_range_view ();
3412 Editor::begin_selection_op_history ()
3414 selection_op_cmd_depth = 0;
3415 selection_op_history_it = 0;
3417 while(!selection_op_history.empty()) {
3418 delete selection_op_history.front();
3419 selection_op_history.pop_front();
3422 selection_undo_action->set_sensitive (false);
3423 selection_redo_action->set_sensitive (false);
3424 selection_op_history.push_front (&_selection_memento->get_state ());
3428 Editor::begin_reversible_selection_op (string name)
3431 //cerr << name << endl;
3432 /* begin/commit pairs can be nested */
3433 selection_op_cmd_depth++;
3438 Editor::commit_reversible_selection_op ()
3441 if (selection_op_cmd_depth == 1) {
3443 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3445 The user has undone some selection ops and then made a new one,
3446 making anything earlier in the list invalid.
3449 list<XMLNode *>::iterator it = selection_op_history.begin();
3450 list<XMLNode *>::iterator e_it = it;
3451 advance (e_it, selection_op_history_it);
3453 for ( ; it != e_it; ++it) {
3456 selection_op_history.erase (selection_op_history.begin(), e_it);
3459 selection_op_history.push_front (&_selection_memento->get_state ());
3460 selection_op_history_it = 0;
3462 selection_undo_action->set_sensitive (true);
3463 selection_redo_action->set_sensitive (false);
3466 if (selection_op_cmd_depth > 0) {
3467 selection_op_cmd_depth--;
3473 Editor::undo_selection_op ()
3476 selection_op_history_it++;
3478 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3479 if (n == selection_op_history_it) {
3480 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3481 selection_redo_action->set_sensitive (true);
3485 /* is there an earlier entry? */
3486 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3487 selection_undo_action->set_sensitive (false);
3493 Editor::redo_selection_op ()
3496 if (selection_op_history_it > 0) {
3497 selection_op_history_it--;
3500 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3501 if (n == selection_op_history_it) {
3502 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3503 selection_undo_action->set_sensitive (true);
3508 if (selection_op_history_it == 0) {
3509 selection_redo_action->set_sensitive (false);
3515 Editor::begin_reversible_command (string name)
3518 before.push_back (&_selection_memento->get_state ());
3519 _session->begin_reversible_command (name);
3524 Editor::begin_reversible_command (GQuark q)
3527 before.push_back (&_selection_memento->get_state ());
3528 _session->begin_reversible_command (q);
3533 Editor::abort_reversible_command ()
3536 while(!before.empty()) {
3537 delete before.front();
3540 _session->abort_reversible_command ();
3545 Editor::commit_reversible_command ()
3548 if (before.size() == 1) {
3549 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3550 redo_action->set_sensitive(false);
3551 undo_action->set_sensitive(true);
3552 begin_selection_op_history ();
3555 if (before.empty()) {
3556 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3561 _session->commit_reversible_command ();
3566 Editor::history_changed ()
3570 if (undo_action && _session) {
3571 if (_session->undo_depth() == 0) {
3572 label = S_("Command|Undo");
3574 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3576 undo_action->property_label() = label;
3579 if (redo_action && _session) {
3580 if (_session->redo_depth() == 0) {
3582 redo_action->set_sensitive (false);
3584 label = string_compose(_("Redo (%1)"), _session->next_redo());
3585 redo_action->set_sensitive (true);
3587 redo_action->property_label() = label;
3592 Editor::duplicate_range (bool with_dialog)
3596 RegionSelection rs = get_regions_from_selection_and_entered ();
3598 if ( selection->time.length() == 0 && rs.empty()) {
3604 ArdourDialog win (_("Duplicate"));
3605 Label label (_("Number of duplications:"));
3606 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3607 SpinButton spinner (adjustment, 0.0, 1);
3610 win.get_vbox()->set_spacing (12);
3611 win.get_vbox()->pack_start (hbox);
3612 hbox.set_border_width (6);
3613 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3615 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3616 place, visually. so do this by hand.
3619 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3620 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3621 spinner.grab_focus();
3627 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3628 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3629 win.set_default_response (RESPONSE_ACCEPT);
3631 spinner.grab_focus ();
3633 switch (win.run ()) {
3634 case RESPONSE_ACCEPT:
3640 times = adjustment.get_value();
3643 if ((current_mouse_mode() == Editing::MouseRange)) {
3644 if (selection->time.length()) {
3645 duplicate_selection (times);
3647 } else if (get_smart_mode()) {
3648 if (selection->time.length()) {
3649 duplicate_selection (times);
3651 duplicate_some_regions (rs, times);
3653 duplicate_some_regions (rs, times);
3658 Editor::set_edit_mode (EditMode m)
3660 Config->set_edit_mode (m);
3664 Editor::cycle_edit_mode ()
3666 switch (Config->get_edit_mode()) {
3668 Config->set_edit_mode (Ripple);
3672 Config->set_edit_mode (Lock);
3675 Config->set_edit_mode (Slide);
3681 Editor::edit_mode_selection_done ( EditMode m )
3683 Config->set_edit_mode ( m );
3687 Editor::snap_type_selection_done (SnapType snaptype)
3689 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3691 ract->set_active ();
3696 Editor::snap_mode_selection_done (SnapMode mode)
3698 RefPtr<RadioAction> ract = snap_mode_action (mode);
3701 ract->set_active (true);
3706 Editor::cycle_edit_point (bool with_marker)
3708 if(Profile->get_mixbus())
3709 with_marker = false;
3711 switch (_edit_point) {
3713 set_edit_point_preference (EditAtPlayhead);
3715 case EditAtPlayhead:
3717 set_edit_point_preference (EditAtSelectedMarker);
3719 set_edit_point_preference (EditAtMouse);
3722 case EditAtSelectedMarker:
3723 set_edit_point_preference (EditAtMouse);
3729 Editor::edit_point_selection_done (EditPoint ep)
3731 set_edit_point_preference ( ep );
3735 Editor::build_zoom_focus_menu ()
3737 using namespace Menu_Helpers;
3739 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3740 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3741 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3742 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3743 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3744 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3746 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3750 Editor::zoom_focus_selection_done ( ZoomFocus f )
3752 RefPtr<RadioAction> ract = zoom_focus_action (f);
3754 ract->set_active ();
3759 Editor::build_track_count_menu ()
3761 using namespace Menu_Helpers;
3763 if (!Profile->get_mixbus()) {
3764 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3765 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3766 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3767 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3768 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3769 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3770 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3771 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3772 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3773 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3774 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3775 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3776 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3778 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3779 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3780 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3781 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3782 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3783 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3784 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3785 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3786 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3787 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3789 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3790 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3791 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3792 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3793 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3794 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3795 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3796 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3797 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3798 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3799 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3804 Editor::set_zoom_preset (int64_t ms)
3807 temporal_zoom_session();
3811 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3812 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3816 Editor::set_visible_track_count (int32_t n)
3818 _visible_track_count = n;
3820 /* if the canvas hasn't really been allocated any size yet, just
3821 record the desired number of visible tracks and return. when canvas
3822 allocation happens, we will get called again and then we can do the
3826 if (_visible_canvas_height <= 1) {
3832 DisplaySuspender ds;
3834 if (_visible_track_count > 0) {
3835 h = trackviews_height() / _visible_track_count;
3836 std::ostringstream s;
3837 s << _visible_track_count;
3839 } else if (_visible_track_count == 0) {
3841 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3842 if ((*i)->marked_for_display()) {
3846 h = trackviews_height() / n;
3849 /* negative value means that the visible track count has
3850 been overridden by explicit track height changes.
3852 visible_tracks_selector.set_text (X_("*"));
3856 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3857 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3860 if (str != visible_tracks_selector.get_text()) {
3861 visible_tracks_selector.set_text (str);
3866 Editor::override_visible_track_count ()
3868 _visible_track_count = -1;
3869 visible_tracks_selector.set_text ( _("*") );
3873 Editor::edit_controls_button_release (GdkEventButton* ev)
3875 if (Keyboard::is_context_menu_event (ev)) {
3876 ARDOUR_UI::instance()->add_route ();
3877 } else if (ev->button == 1) {
3878 selection->clear_tracks ();
3885 Editor::mouse_select_button_release (GdkEventButton* ev)
3887 /* this handles just right-clicks */
3889 if (ev->button != 3) {
3897 Editor::set_zoom_focus (ZoomFocus f)
3899 string str = zoom_focus_strings[(int)f];
3901 if (str != zoom_focus_selector.get_text()) {
3902 zoom_focus_selector.set_text (str);
3905 if (zoom_focus != f) {
3912 Editor::cycle_zoom_focus ()
3914 switch (zoom_focus) {
3916 set_zoom_focus (ZoomFocusRight);
3918 case ZoomFocusRight:
3919 set_zoom_focus (ZoomFocusCenter);
3921 case ZoomFocusCenter:
3922 set_zoom_focus (ZoomFocusPlayhead);
3924 case ZoomFocusPlayhead:
3925 set_zoom_focus (ZoomFocusMouse);
3927 case ZoomFocusMouse:
3928 set_zoom_focus (ZoomFocusEdit);
3931 set_zoom_focus (ZoomFocusLeft);
3937 Editor::set_show_measures (bool yn)
3939 if (_show_measures != yn) {
3942 if ((_show_measures = yn) == true) {
3944 tempo_lines->show();
3947 std::vector<TempoMap::BBTPoint> grid;
3948 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3949 draw_measures (grid);
3957 Editor::toggle_follow_playhead ()
3959 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3961 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3962 set_follow_playhead (tact->get_active());
3966 /** @param yn true to follow playhead, otherwise false.
3967 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3970 Editor::set_follow_playhead (bool yn, bool catch_up)
3972 if (_follow_playhead != yn) {
3973 if ((_follow_playhead = yn) == true && catch_up) {
3975 reset_x_origin_to_follow_playhead ();
3982 Editor::toggle_stationary_playhead ()
3984 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3986 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3987 set_stationary_playhead (tact->get_active());
3992 Editor::set_stationary_playhead (bool yn)
3994 if (_stationary_playhead != yn) {
3995 if ((_stationary_playhead = yn) == true) {
3997 // FIXME need a 3.0 equivalent of this 2.X call
3998 // update_current_screen ();
4005 Editor::playlist_selector () const
4007 return *_playlist_selector;
4011 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4013 if (paste_count == 0) {
4014 /* don't bother calculating an offset that will be zero anyway */
4018 /* calculate basic unsnapped multi-paste offset */
4019 framecnt_t offset = paste_count * duration;
4021 /* snap offset so pos + offset is aligned to the grid */
4022 framepos_t offset_pos = pos + offset;
4023 snap_to(offset_pos, RoundUpMaybe);
4024 offset = offset_pos - pos;
4030 Editor::get_grid_beat_divisions(framepos_t position)
4032 switch (_snap_type) {
4033 case SnapToBeatDiv128: return 128;
4034 case SnapToBeatDiv64: return 64;
4035 case SnapToBeatDiv32: return 32;
4036 case SnapToBeatDiv28: return 28;
4037 case SnapToBeatDiv24: return 24;
4038 case SnapToBeatDiv20: return 20;
4039 case SnapToBeatDiv16: return 16;
4040 case SnapToBeatDiv14: return 14;
4041 case SnapToBeatDiv12: return 12;
4042 case SnapToBeatDiv10: return 10;
4043 case SnapToBeatDiv8: return 8;
4044 case SnapToBeatDiv7: return 7;
4045 case SnapToBeatDiv6: return 6;
4046 case SnapToBeatDiv5: return 5;
4047 case SnapToBeatDiv4: return 4;
4048 case SnapToBeatDiv3: return 3;
4049 case SnapToBeatDiv2: return 2;
4055 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4056 if the grid is non-musical, returns 0.
4057 if the grid is snapped to bars, returns -1.
4058 @param event_state the current keyboard modifier mask.
4061 Editor::get_grid_music_divisions (uint32_t event_state)
4063 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4067 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4071 switch (_snap_type) {
4072 case SnapToBeatDiv128: return 128;
4073 case SnapToBeatDiv64: return 64;
4074 case SnapToBeatDiv32: return 32;
4075 case SnapToBeatDiv28: return 28;
4076 case SnapToBeatDiv24: return 24;
4077 case SnapToBeatDiv20: return 20;
4078 case SnapToBeatDiv16: return 16;
4079 case SnapToBeatDiv14: return 14;
4080 case SnapToBeatDiv12: return 12;
4081 case SnapToBeatDiv10: return 10;
4082 case SnapToBeatDiv8: return 8;
4083 case SnapToBeatDiv7: return 7;
4084 case SnapToBeatDiv6: return 6;
4085 case SnapToBeatDiv5: return 5;
4086 case SnapToBeatDiv4: return 4;
4087 case SnapToBeatDiv3: return 3;
4088 case SnapToBeatDiv2: return 2;
4089 case SnapToBeat: return 1;
4090 case SnapToBar : return -1;
4097 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4101 const unsigned divisions = get_grid_beat_divisions(position);
4103 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4106 switch (_snap_type) {
4108 return Evoral::Beats(1.0);
4111 return Evoral::Beats(_session->tempo_map().meter_at_frame (position).divisions_per_bar());
4119 return Evoral::Beats();
4123 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4127 ret = nudge_clock->current_duration (pos);
4128 next = ret + 1; /* XXXX fix me */
4134 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4136 ArdourDialog dialog (_("Playlist Deletion"));
4137 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4138 "If it is kept, its audio files will not be cleaned.\n"
4139 "If it is deleted, audio files used by it alone will be cleaned."),
4142 dialog.set_position (WIN_POS_CENTER);
4143 dialog.get_vbox()->pack_start (label);
4147 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4148 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4149 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4150 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4151 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4153 // by default gtk uses the left most button
4154 keep->grab_focus ();
4156 switch (dialog.run ()) {
4158 /* keep this and all remaining ones */
4163 /* delete this and all others */
4167 case RESPONSE_ACCEPT:
4168 /* delete the playlist */
4172 case RESPONSE_REJECT:
4173 /* keep the playlist */
4185 Editor::audio_region_selection_covers (framepos_t where)
4187 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4188 if ((*a)->region()->covers (where)) {
4197 Editor::prepare_for_cleanup ()
4199 cut_buffer->clear_regions ();
4200 cut_buffer->clear_playlists ();
4202 selection->clear_regions ();
4203 selection->clear_playlists ();
4205 _regions->suspend_redisplay ();
4209 Editor::finish_cleanup ()
4211 _regions->resume_redisplay ();
4215 Editor::transport_loop_location()
4218 return _session->locations()->auto_loop_location();
4225 Editor::transport_punch_location()
4228 return _session->locations()->auto_punch_location();
4235 Editor::control_layout_scroll (GdkEventScroll* ev)
4237 /* Just forward to the normal canvas scroll method. The coordinate
4238 systems are different but since the canvas is always larger than the
4239 track headers, and aligned with the trackview area, this will work.
4241 In the not too distant future this layout is going away anyway and
4242 headers will be on the canvas.
4244 return canvas_scroll_event (ev, false);
4248 Editor::session_state_saved (string)
4251 _snapshots->redisplay ();
4255 Editor::maximise_editing_space ()
4261 Gtk::Window* toplevel = current_toplevel();
4264 toplevel->fullscreen ();
4270 Editor::restore_editing_space ()
4276 Gtk::Window* toplevel = current_toplevel();
4279 toplevel->unfullscreen();
4285 * Make new playlists for a given track and also any others that belong
4286 * to the same active route group with the `select' property.
4291 Editor::new_playlists (TimeAxisView* v)
4293 begin_reversible_command (_("new playlists"));
4294 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4295 _session->playlists->get (playlists);
4296 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4297 commit_reversible_command ();
4301 * Use a copy of the current playlist for a given track and also any others that belong
4302 * to the same active route group with the `select' property.
4307 Editor::copy_playlists (TimeAxisView* v)
4309 begin_reversible_command (_("copy playlists"));
4310 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4311 _session->playlists->get (playlists);
4312 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4313 commit_reversible_command ();
4316 /** Clear the current playlist for a given track and also any others that belong
4317 * to the same active route group with the `select' property.
4322 Editor::clear_playlists (TimeAxisView* v)
4324 begin_reversible_command (_("clear playlists"));
4325 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4326 _session->playlists->get (playlists);
4327 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4328 commit_reversible_command ();
4332 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4334 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4338 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4340 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4344 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4346 atv.clear_playlist ();
4350 Editor::get_y_origin () const
4352 return vertical_adjustment.get_value ();
4355 /** Queue up a change to the viewport x origin.
4356 * @param frame New x origin.
4359 Editor::reset_x_origin (framepos_t frame)
4361 pending_visual_change.add (VisualChange::TimeOrigin);
4362 pending_visual_change.time_origin = frame;
4363 ensure_visual_change_idle_handler ();
4367 Editor::reset_y_origin (double y)
4369 pending_visual_change.add (VisualChange::YOrigin);
4370 pending_visual_change.y_origin = y;
4371 ensure_visual_change_idle_handler ();
4375 Editor::reset_zoom (framecnt_t spp)
4377 if (spp == samples_per_pixel) {
4381 pending_visual_change.add (VisualChange::ZoomLevel);
4382 pending_visual_change.samples_per_pixel = spp;
4383 ensure_visual_change_idle_handler ();
4387 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4389 reset_x_origin (frame);
4392 if (!no_save_visual) {
4393 undo_visual_stack.push_back (current_visual_state(false));
4397 Editor::VisualState::VisualState (bool with_tracks)
4398 : gui_state (with_tracks ? new GUIObjectState : 0)
4402 Editor::VisualState::~VisualState ()
4407 Editor::VisualState*
4408 Editor::current_visual_state (bool with_tracks)
4410 VisualState* vs = new VisualState (with_tracks);
4411 vs->y_position = vertical_adjustment.get_value();
4412 vs->samples_per_pixel = samples_per_pixel;
4413 vs->leftmost_frame = leftmost_frame;
4414 vs->zoom_focus = zoom_focus;
4417 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4424 Editor::undo_visual_state ()
4426 if (undo_visual_stack.empty()) {
4430 VisualState* vs = undo_visual_stack.back();
4431 undo_visual_stack.pop_back();
4434 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4437 use_visual_state (*vs);
4442 Editor::redo_visual_state ()
4444 if (redo_visual_stack.empty()) {
4448 VisualState* vs = redo_visual_stack.back();
4449 redo_visual_stack.pop_back();
4451 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4452 // why do we check here?
4453 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4456 use_visual_state (*vs);
4461 Editor::swap_visual_state ()
4463 if (undo_visual_stack.empty()) {
4464 redo_visual_state ();
4466 undo_visual_state ();
4471 Editor::use_visual_state (VisualState& vs)
4473 PBD::Unwinder<bool> nsv (no_save_visual, true);
4474 DisplaySuspender ds;
4476 vertical_adjustment.set_value (vs.y_position);
4478 set_zoom_focus (vs.zoom_focus);
4479 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4482 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4484 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4485 (*i)->clear_property_cache();
4486 (*i)->reset_visual_state ();
4490 _routes->update_visibility ();
4493 /** This is the core function that controls the zoom level of the canvas. It is called
4494 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4495 * @param spp new number of samples per pixel
4498 Editor::set_samples_per_pixel (framecnt_t spp)
4504 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4505 const framecnt_t lots_of_pixels = 4000;
4507 /* if the zoom level is greater than what you'd get trying to display 3
4508 * days of audio on a really big screen, then it's too big.
4511 if (spp * lots_of_pixels > three_days) {
4515 samples_per_pixel = spp;
4518 tempo_lines->tempo_map_changed();
4521 bool const showing_time_selection = selection->time.length() > 0;
4523 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4524 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4525 (*i)->reshow_selection (selection->time);
4529 ZoomChanged (); /* EMIT_SIGNAL */
4531 ArdourCanvas::GtkCanvasViewport* c;
4533 c = get_track_canvas();
4535 c->canvas()->zoomed ();
4538 if (playhead_cursor) {
4539 playhead_cursor->set_position (playhead_cursor->current_frame ());
4542 refresh_location_display();
4543 _summary->set_overlays_dirty ();
4545 update_marker_labels ();
4551 Editor::queue_visual_videotimeline_update ()
4554 * pending_visual_change.add (VisualChange::VideoTimeline);
4555 * or maybe even more specific: which videotimeline-image
4556 * currently it calls update_video_timeline() to update
4557 * _all outdated_ images on the video-timeline.
4558 * see 'exposeimg()' in video_image_frame.cc
4560 ensure_visual_change_idle_handler ();
4564 Editor::ensure_visual_change_idle_handler ()
4566 if (pending_visual_change.idle_handler_id < 0) {
4567 // see comment in add_to_idle_resize above.
4568 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4569 pending_visual_change.being_handled = false;
4574 Editor::_idle_visual_changer (void* arg)
4576 return static_cast<Editor*>(arg)->idle_visual_changer ();
4580 Editor::idle_visual_changer ()
4582 /* set_horizontal_position() below (and maybe other calls) call
4583 gtk_main_iteration(), so it's possible that a signal will be handled
4584 half-way through this method. If this signal wants an
4585 idle_visual_changer we must schedule another one after this one, so
4586 mark the idle_handler_id as -1 here to allow that. Also make a note
4587 that we are doing the visual change, so that changes in response to
4588 super-rapid-screen-update can be dropped if we are still processing
4592 pending_visual_change.idle_handler_id = -1;
4593 pending_visual_change.being_handled = true;
4595 VisualChange vc = pending_visual_change;
4597 pending_visual_change.pending = (VisualChange::Type) 0;
4599 visual_changer (vc);
4601 pending_visual_change.being_handled = false;
4603 return 0; /* this is always a one-shot call */
4607 Editor::visual_changer (const VisualChange& vc)
4609 double const last_time_origin = horizontal_position ();
4611 if (vc.pending & VisualChange::ZoomLevel) {
4612 set_samples_per_pixel (vc.samples_per_pixel);
4614 compute_fixed_ruler_scale ();
4616 std::vector<TempoMap::BBTPoint> grid;
4617 compute_current_bbt_points (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4618 compute_bbt_ruler_scale (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4619 update_tempo_based_rulers (grid);
4621 update_video_timeline();
4624 if (vc.pending & VisualChange::TimeOrigin) {
4625 set_horizontal_position (vc.time_origin / samples_per_pixel);
4628 if (vc.pending & VisualChange::YOrigin) {
4629 vertical_adjustment.set_value (vc.y_origin);
4632 if (last_time_origin == horizontal_position ()) {
4633 /* changed signal not emitted */
4634 update_fixed_rulers ();
4635 redisplay_tempo (true);
4638 if (!(vc.pending & VisualChange::ZoomLevel)) {
4639 update_video_timeline();
4642 _summary->set_overlays_dirty ();
4645 struct EditorOrderTimeAxisSorter {
4646 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4647 return a->order () < b->order ();
4652 Editor::sort_track_selection (TrackViewList& sel)
4654 EditorOrderTimeAxisSorter cmp;
4659 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4662 framepos_t where = 0;
4663 EditPoint ep = _edit_point;
4665 if (Profile->get_mixbus())
4666 if (ep == EditAtSelectedMarker)
4667 ep = EditAtPlayhead;
4669 if (from_outside_canvas && (ep == EditAtMouse)) {
4670 ep = EditAtPlayhead;
4671 } else if (from_context_menu && (ep == EditAtMouse)) {
4672 return canvas_event_sample (&context_click_event, 0, 0);
4675 if (entered_marker) {
4676 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4677 return entered_marker->position();
4680 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4681 ep = EditAtSelectedMarker;
4684 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4685 ep = EditAtPlayhead;
4689 case EditAtPlayhead:
4690 if (_dragging_playhead) {
4691 where = *_control_scroll_target;
4693 where = _session->audible_frame();
4695 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4698 case EditAtSelectedMarker:
4699 if (!selection->markers.empty()) {
4701 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4704 where = loc->start();
4708 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4716 if (!mouse_frame (where, ignored)) {
4717 /* XXX not right but what can we do ? */
4721 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4729 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4731 if (!_session) return;
4733 begin_reversible_command (cmd);
4737 if ((tll = transport_loop_location()) == 0) {
4738 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4739 XMLNode &before = _session->locations()->get_state();
4740 _session->locations()->add (loc, true);
4741 _session->set_auto_loop_location (loc);
4742 XMLNode &after = _session->locations()->get_state();
4743 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4745 XMLNode &before = tll->get_state();
4746 tll->set_hidden (false, this);
4747 tll->set (start, end);
4748 XMLNode &after = tll->get_state();
4749 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4752 commit_reversible_command ();
4756 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4758 if (!_session) return;
4760 begin_reversible_command (cmd);
4764 if ((tpl = transport_punch_location()) == 0) {
4765 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4766 XMLNode &before = _session->locations()->get_state();
4767 _session->locations()->add (loc, true);
4768 _session->set_auto_punch_location (loc);
4769 XMLNode &after = _session->locations()->get_state();
4770 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4772 XMLNode &before = tpl->get_state();
4773 tpl->set_hidden (false, this);
4774 tpl->set (start, end);
4775 XMLNode &after = tpl->get_state();
4776 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4779 commit_reversible_command ();
4782 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4783 * @param rs List to which found regions are added.
4784 * @param where Time to look at.
4785 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4788 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4790 const TrackViewList* tracks;
4793 tracks = &track_views;
4798 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4800 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4803 boost::shared_ptr<Track> tr;
4804 boost::shared_ptr<Playlist> pl;
4806 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4808 boost::shared_ptr<RegionList> regions = pl->regions_at (
4809 (framepos_t) floor ( (double) where * tr->speed()));
4811 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4812 RegionView* rv = rtv->view()->find_view (*i);
4823 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4825 const TrackViewList* tracks;
4828 tracks = &track_views;
4833 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4834 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4836 boost::shared_ptr<Track> tr;
4837 boost::shared_ptr<Playlist> pl;
4839 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4841 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4842 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4844 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4846 RegionView* rv = rtv->view()->find_view (*i);
4857 /** Get regions using the following method:
4859 * Make a region list using:
4860 * (a) any selected regions
4861 * (b) the intersection of any selected tracks and the edit point(*)
4862 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4864 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4866 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4870 Editor::get_regions_from_selection_and_edit_point ()
4872 RegionSelection regions;
4874 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4875 regions.add (entered_regionview);
4877 regions = selection->regions;
4880 if ( regions.empty() ) {
4881 TrackViewList tracks = selection->tracks;
4883 if (!tracks.empty()) {
4884 /* no region selected or entered, but some selected tracks:
4885 * act on all regions on the selected tracks at the edit point
4887 framepos_t const where = get_preferred_edit_position ();
4888 get_regions_at(regions, where, tracks);
4895 /** Get regions using the following method:
4897 * Make a region list using:
4898 * (a) any selected regions
4899 * (b) the intersection of any selected tracks and the edit point(*)
4900 * (c) if neither exists, then whatever region is under the mouse
4902 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4904 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4907 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4909 RegionSelection regions;
4911 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4912 regions.add (entered_regionview);
4914 regions = selection->regions;
4917 if ( regions.empty() ) {
4918 TrackViewList tracks = selection->tracks;
4920 if (!tracks.empty()) {
4921 /* no region selected or entered, but some selected tracks:
4922 * act on all regions on the selected tracks at the edit point
4924 get_regions_at(regions, pos, tracks);
4931 /** Start with regions that are selected, or the entered regionview if none are selected.
4932 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4933 * of the regions that we started with.
4937 Editor::get_regions_from_selection_and_entered () const
4939 RegionSelection regions = selection->regions;
4941 if (regions.empty() && entered_regionview) {
4942 regions.add (entered_regionview);
4949 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4951 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4952 RouteTimeAxisView* rtav;
4954 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4955 boost::shared_ptr<Playlist> pl;
4956 std::vector<boost::shared_ptr<Region> > results;
4957 boost::shared_ptr<Track> tr;
4959 if ((tr = rtav->track()) == 0) {
4964 if ((pl = (tr->playlist())) != 0) {
4965 boost::shared_ptr<Region> r = pl->region_by_id (id);
4967 RegionView* rv = rtav->view()->find_view (r);
4969 regions.push_back (rv);
4978 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4981 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4982 MidiTimeAxisView* mtav;
4984 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4986 mtav->get_per_region_note_selection (selection);
4993 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4995 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4997 RouteTimeAxisView* tatv;
4999 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5001 boost::shared_ptr<Playlist> pl;
5002 vector<boost::shared_ptr<Region> > results;
5004 boost::shared_ptr<Track> tr;
5006 if ((tr = tatv->track()) == 0) {
5011 if ((pl = (tr->playlist())) != 0) {
5012 if (src_comparison) {
5013 pl->get_source_equivalent_regions (region, results);
5015 pl->get_region_list_equivalent_regions (region, results);
5019 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5020 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5021 regions.push_back (marv);
5030 Editor::show_rhythm_ferret ()
5032 if (rhythm_ferret == 0) {
5033 rhythm_ferret = new RhythmFerret(*this);
5036 rhythm_ferret->set_session (_session);
5037 rhythm_ferret->show ();
5038 rhythm_ferret->present ();
5042 Editor::first_idle ()
5044 MessageDialog* dialog = 0;
5046 if (track_views.size() > 1) {
5047 Timers::TimerSuspender t;
5048 dialog = new MessageDialog (
5049 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5053 ARDOUR_UI::instance()->flush_pending (60);
5056 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5060 // first idle adds route children (automation tracks), so we need to redisplay here
5061 _routes->redisplay ();
5065 if (_session->undo_depth() == 0) {
5066 undo_action->set_sensitive(false);
5068 redo_action->set_sensitive(false);
5069 begin_selection_op_history ();
5075 Editor::_idle_resize (gpointer arg)
5077 return ((Editor*)arg)->idle_resize ();
5081 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5083 if (resize_idle_id < 0) {
5084 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5085 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5086 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5088 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5089 _pending_resize_amount = 0;
5092 /* make a note of the smallest resulting height, so that we can clamp the
5093 lower limit at TimeAxisView::hSmall */
5095 int32_t min_resulting = INT32_MAX;
5097 _pending_resize_amount += h;
5098 _pending_resize_view = view;
5100 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5102 if (selection->tracks.contains (_pending_resize_view)) {
5103 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5104 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5108 if (min_resulting < 0) {
5113 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5114 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5118 /** Handle pending resizing of tracks */
5120 Editor::idle_resize ()
5122 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5124 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5125 selection->tracks.contains (_pending_resize_view)) {
5127 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5128 if (*i != _pending_resize_view) {
5129 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5134 _pending_resize_amount = 0;
5135 _group_tabs->set_dirty ();
5136 resize_idle_id = -1;
5144 ENSURE_GUI_THREAD (*this, &Editor::located);
5147 playhead_cursor->set_position (_session->audible_frame ());
5148 if (_follow_playhead && !_pending_initial_locate) {
5149 reset_x_origin_to_follow_playhead ();
5153 _pending_locate_request = false;
5154 _pending_initial_locate = false;
5158 Editor::region_view_added (RegionView * rv)
5160 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5161 if (rv->region ()->id () == (*pr)) {
5162 selection->add (rv);
5163 selection->regions.pending.erase (pr);
5168 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5170 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5171 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5172 if (rv->region()->id () == (*rnote).first) {
5173 mrv->select_notes ((*rnote).second);
5174 selection->pending_midi_note_selection.erase(rnote);
5180 _summary->set_background_dirty ();
5184 Editor::region_view_removed ()
5186 _summary->set_background_dirty ();
5190 Editor::axis_view_from_stripable (boost::shared_ptr<Stripable> s) const
5192 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5193 if ((*j)->stripable() == s) {
5203 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5207 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5208 TimeAxisView* tv = axis_view_from_stripable (*i);
5218 Editor::suspend_route_redisplay ()
5221 _routes->suspend_redisplay();
5226 Editor::resume_route_redisplay ()
5229 _routes->redisplay(); // queue redisplay
5230 _routes->resume_redisplay();
5235 Editor::add_vcas (VCAList& vlist)
5239 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5240 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5243 add_stripables (sl);
5247 Editor::add_routes (RouteList& rlist)
5251 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5255 add_stripables (sl);
5259 Editor::add_stripables (StripableList& sl)
5261 list<TimeAxisView*> new_views;
5262 boost::shared_ptr<VCA> v;
5263 boost::shared_ptr<Route> r;
5264 TrackViewList new_selection;
5265 bool from_scratch = (track_views.size() == 0);
5267 sl.sort (StripablePresentationInfoSorter());
5269 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5271 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5273 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5275 new_views.push_back (vtv);
5277 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5279 if (r->is_auditioner() || r->is_monitor()) {
5283 RouteTimeAxisView* rtv;
5284 DataType dt = r->input()->default_type();
5286 if (dt == ARDOUR::DataType::AUDIO) {
5287 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5289 } else if (dt == ARDOUR::DataType::MIDI) {
5290 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5293 throw unknown_type();
5296 new_views.push_back (rtv);
5297 track_views.push_back (rtv);
5298 new_selection.push_back (rtv);
5300 rtv->effective_gain_display ();
5302 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5303 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5307 if (new_views.size() > 0) {
5308 _routes->time_axis_views_added (new_views);
5309 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5312 /* note: !new_selection.empty() means that we got some routes rather
5316 if (!from_scratch && !new_selection.empty()) {
5317 selection->tracks.clear();
5318 selection->add (new_selection);
5319 begin_selection_op_history();
5322 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5323 show_editor_mixer (true);
5326 editor_list_button.set_sensitive (true);
5330 Editor::timeaxisview_deleted (TimeAxisView *tv)
5332 if (tv == entered_track) {
5336 if (_session && _session->deletion_in_progress()) {
5337 /* the situation is under control */
5341 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5343 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5345 _routes->route_removed (tv);
5347 TimeAxisView::Children c = tv->get_child_list ();
5348 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5349 if (entered_track == i->get()) {
5354 /* remove it from the list of track views */
5356 TrackViewList::iterator i;
5358 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5359 i = track_views.erase (i);
5362 /* update whatever the current mixer strip is displaying, if revelant */
5364 boost::shared_ptr<Route> route;
5367 route = rtav->route ();
5370 if (current_mixer_strip && current_mixer_strip->route() == route) {
5372 TimeAxisView* next_tv;
5374 if (track_views.empty()) {
5376 } else if (i == track_views.end()) {
5377 next_tv = track_views.front();
5384 set_selected_mixer_strip (*next_tv);
5386 /* make the editor mixer strip go away setting the
5387 * button to inactive (which also unticks the menu option)
5390 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5396 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5398 if (apply_to_selection) {
5399 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5401 TrackSelection::iterator j = i;
5404 hide_track_in_display (*i, false);
5409 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5411 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5412 // this will hide the mixer strip
5413 set_selected_mixer_strip (*tv);
5416 _routes->hide_track_in_display (*tv);
5421 Editor::sync_track_view_list_and_routes ()
5423 track_views = TrackViewList (_routes->views ());
5425 _summary->set_background_dirty();
5426 _group_tabs->set_dirty ();
5428 return false; // do not call again (until needed)
5432 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5434 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5439 /** Find a RouteTimeAxisView by the ID of its route */
5441 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5443 RouteTimeAxisView* v;
5445 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5446 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5447 if(v->route()->id() == id) {
5457 Editor::fit_route_group (RouteGroup *g)
5459 TrackViewList ts = axis_views_from_routes (g->route_list ());
5464 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5466 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5469 _session->cancel_audition ();
5473 if (_session->is_auditioning()) {
5474 _session->cancel_audition ();
5475 if (r == last_audition_region) {
5480 _session->audition_region (r);
5481 last_audition_region = r;
5486 Editor::hide_a_region (boost::shared_ptr<Region> r)
5488 r->set_hidden (true);
5492 Editor::show_a_region (boost::shared_ptr<Region> r)
5494 r->set_hidden (false);
5498 Editor::audition_region_from_region_list ()
5500 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5504 Editor::hide_region_from_region_list ()
5506 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5510 Editor::show_region_in_region_list ()
5512 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5516 Editor::step_edit_status_change (bool yn)
5519 start_step_editing ();
5521 stop_step_editing ();
5526 Editor::start_step_editing ()
5528 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5532 Editor::stop_step_editing ()
5534 step_edit_connection.disconnect ();
5538 Editor::check_step_edit ()
5540 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5541 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5543 mtv->check_step_edit ();
5547 return true; // do it again, till we stop
5551 Editor::scroll_press (Direction dir)
5553 ++_scroll_callbacks;
5555 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5556 /* delay the first auto-repeat */
5562 scroll_backward (1);
5570 scroll_up_one_track ();
5574 scroll_down_one_track ();
5578 /* do hacky auto-repeat */
5579 if (!_scroll_connection.connected ()) {
5581 _scroll_connection = Glib::signal_timeout().connect (
5582 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5585 _scroll_callbacks = 0;
5592 Editor::scroll_release ()
5594 _scroll_connection.disconnect ();
5597 /** Queue a change for the Editor viewport x origin to follow the playhead */
5599 Editor::reset_x_origin_to_follow_playhead ()
5601 framepos_t const frame = playhead_cursor->current_frame ();
5603 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5605 if (_session->transport_speed() < 0) {
5607 if (frame > (current_page_samples() / 2)) {
5608 center_screen (frame-(current_page_samples()/2));
5610 center_screen (current_page_samples()/2);
5617 if (frame < leftmost_frame) {
5619 if (_session->transport_rolling()) {
5620 /* rolling; end up with the playhead at the right of the page */
5621 l = frame - current_page_samples ();
5623 /* not rolling: end up with the playhead 1/4 of the way along the page */
5624 l = frame - current_page_samples() / 4;
5628 if (_session->transport_rolling()) {
5629 /* rolling: end up with the playhead on the left of the page */
5632 /* not rolling: end up with the playhead 3/4 of the way along the page */
5633 l = frame - 3 * current_page_samples() / 4;
5641 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5647 Editor::super_rapid_screen_update ()
5649 if (!_session || !_session->engine().running()) {
5653 /* METERING / MIXER STRIPS */
5655 /* update track meters, if required */
5656 if (contents().is_mapped() && meters_running) {
5657 RouteTimeAxisView* rtv;
5658 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5659 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5660 rtv->fast_update ();
5665 /* and any current mixer strip */
5666 if (current_mixer_strip) {
5667 current_mixer_strip->fast_update ();
5670 /* PLAYHEAD AND VIEWPORT */
5672 framepos_t const frame = _session->audible_frame();
5674 /* There are a few reasons why we might not update the playhead / viewport stuff:
5676 * 1. we don't update things when there's a pending locate request, otherwise
5677 * when the editor requests a locate there is a chance that this method
5678 * will move the playhead before the locate request is processed, causing
5680 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5681 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5684 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5686 last_update_frame = frame;
5688 if (!_dragging_playhead) {
5689 playhead_cursor->set_position (frame);
5692 if (!_stationary_playhead) {
5694 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5695 /* We only do this if we aren't already
5696 handling a visual change (ie if
5697 pending_visual_change.being_handled is
5698 false) so that these requests don't stack
5699 up there are too many of them to handle in
5702 reset_x_origin_to_follow_playhead ();
5707 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5708 framepos_t const frame = playhead_cursor->current_frame ();
5709 double target = ((double)frame - (double)current_page_samples()/2.0);
5710 if (target <= 0.0) {
5713 // compare to EditorCursor::set_position()
5714 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5715 double const new_pos = sample_to_pixel_unrounded (target);
5716 if (rint (new_pos) != rint (old_pos)) {
5717 reset_x_origin (pixel_to_sample (floor (new_pos)));
5728 Editor::session_going_away ()
5730 _have_idled = false;
5732 _session_connections.drop_connections ();
5734 super_rapid_screen_update_connection.disconnect ();
5736 selection->clear ();
5737 cut_buffer->clear ();
5739 clicked_regionview = 0;
5740 clicked_axisview = 0;
5741 clicked_routeview = 0;
5742 entered_regionview = 0;
5744 last_update_frame = 0;
5747 playhead_cursor->hide ();
5749 /* rip everything out of the list displays */
5753 _route_groups->clear ();
5755 /* do this first so that deleting a track doesn't reset cms to null
5756 and thus cause a leak.
5759 if (current_mixer_strip) {
5760 if (current_mixer_strip->get_parent() != 0) {
5761 global_hpacker.remove (*current_mixer_strip);
5763 delete current_mixer_strip;
5764 current_mixer_strip = 0;
5767 /* delete all trackviews */
5769 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5772 track_views.clear ();
5774 nudge_clock->set_session (0);
5776 editor_list_button.set_active(false);
5777 editor_list_button.set_sensitive(false);
5779 /* clear tempo/meter rulers */
5780 remove_metric_marks ();
5782 clear_marker_display ();
5784 stop_step_editing ();
5788 /* get rid of any existing editor mixer strip */
5790 WindowTitle title(Glib::get_application_name());
5791 title += _("Editor");
5793 own_window()->set_title (title.get_string());
5796 SessionHandlePtr::session_going_away ();
5800 Editor::trigger_script (int i)
5802 LuaInstance::instance()-> call_action (i);
5806 Editor::set_script_action_name (int i, const std::string& n)
5808 string const a = string_compose (X_("script-action-%1"), i + 1);
5809 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5812 act->set_label (string_compose (_("Unset #%1"), i + 1));
5813 act->set_tooltip (_("no action bound"));
5814 act->set_sensitive (false);
5817 act->set_tooltip (n);
5818 act->set_sensitive (true);
5820 KeyEditor::UpdateBindings ();
5824 Editor::show_editor_list (bool yn)
5827 _the_notebook.show ();
5829 _the_notebook.hide ();
5834 Editor::change_region_layering_order (bool from_context_menu)
5836 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5838 if (!clicked_routeview) {
5839 if (layering_order_editor) {
5840 layering_order_editor->hide ();
5845 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5851 boost::shared_ptr<Playlist> pl = track->playlist();
5857 if (layering_order_editor == 0) {
5858 layering_order_editor = new RegionLayeringOrderEditor (*this);
5861 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5862 layering_order_editor->maybe_present ();
5866 Editor::update_region_layering_order_editor ()
5868 if (layering_order_editor && layering_order_editor->is_visible ()) {
5869 change_region_layering_order (true);
5874 Editor::setup_fade_images ()
5876 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5877 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5878 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5879 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5880 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5882 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5883 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5884 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5885 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5886 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5888 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5889 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5890 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5891 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5892 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5894 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5895 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5896 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5897 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5898 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5902 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5904 Editor::action_menu_item (std::string const & name)
5906 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5909 return *manage (a->create_menu_item ());
5913 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5915 EventBox* b = manage (new EventBox);
5916 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5917 Label* l = manage (new Label (name));
5921 _the_notebook.append_page (widget, *b);
5925 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5927 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5928 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5931 if (ev->type == GDK_2BUTTON_PRESS) {
5933 /* double-click on a notebook tab shrinks or expands the notebook */
5935 if (_notebook_shrunk) {
5936 if (pre_notebook_shrink_pane_width) {
5937 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
5939 _notebook_shrunk = false;
5941 pre_notebook_shrink_pane_width = edit_pane.get_divider();
5943 /* this expands the LHS of the edit pane to cover the notebook
5944 PAGE but leaves the tabs visible.
5946 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
5947 _notebook_shrunk = true;
5955 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5957 using namespace Menu_Helpers;
5959 MenuList& items = _control_point_context_menu.items ();
5962 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5963 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5964 if (!can_remove_control_point (item)) {
5965 items.back().set_sensitive (false);
5968 _control_point_context_menu.popup (event->button.button, event->button.time);
5972 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5974 using namespace Menu_Helpers;
5976 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5981 /* We need to get the selection here and pass it to the operations, since
5982 popping up the menu will cause a region leave event which clears
5983 entered_regionview. */
5985 MidiRegionView& mrv = note->region_view();
5986 const RegionSelection rs = get_regions_from_selection_and_entered ();
5987 const uint32_t sel_size = mrv.selection_size ();
5989 MenuList& items = _note_context_menu.items();
5993 items.push_back(MenuElem(_("Delete"),
5994 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5997 items.push_back(MenuElem(_("Edit..."),
5998 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5999 if (sel_size != 1) {
6000 items.back().set_sensitive (false);
6003 items.push_back(MenuElem(_("Transpose..."),
6004 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6007 items.push_back(MenuElem(_("Legatize"),
6008 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6010 items.back().set_sensitive (false);
6013 items.push_back(MenuElem(_("Quantize..."),
6014 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6016 items.push_back(MenuElem(_("Remove Overlap"),
6017 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6019 items.back().set_sensitive (false);
6022 items.push_back(MenuElem(_("Transform..."),
6023 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6025 _note_context_menu.popup (event->button.button, event->button.time);
6029 Editor::zoom_vertical_modifier_released()
6031 _stepping_axis_view = 0;
6035 Editor::ui_parameter_changed (string parameter)
6037 if (parameter == "icon-set") {
6038 while (!_cursor_stack.empty()) {
6039 _cursor_stack.pop_back();
6041 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6042 _cursor_stack.push_back(_cursors->grabber);
6043 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6044 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6046 } else if (parameter == "draggable-playhead") {
6047 if (_verbose_cursor) {
6048 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6054 Editor::use_own_window (bool and_fill_it)
6056 bool new_window = !own_window();
6058 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6060 if (win && new_window) {
6061 win->set_name ("EditorWindow");
6063 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6065 // win->signal_realize().connect (*this, &Editor::on_realize);
6066 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6067 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6068 win->set_data ("ardour-bindings", bindings);
6073 DisplaySuspender ds;
6074 contents().show_all ();
6076 /* XXX: this is a bit unfortunate; it would probably
6077 be nicer if we could just call show () above rather
6078 than needing the show_all ()
6081 /* re-hide stuff if necessary */
6082 editor_list_button_toggled ();
6083 parameter_changed ("show-summary");
6084 parameter_changed ("show-group-tabs");
6085 parameter_changed ("show-zoom-tools");
6087 /* now reset all audio_time_axis heights, because widgets might need
6093 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6094 tv = (static_cast<TimeAxisView*>(*i));
6095 tv->reset_height ();
6098 if (current_mixer_strip) {
6099 current_mixer_strip->hide_things ();
6100 current_mixer_strip->parameter_changed ("mixer-element-visibility");