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/eventboxext.h"
61 #include "gtkmm2ext/grouped_buttons.h"
62 #include "gtkmm2ext/gtk_ui.h"
63 #include <gtkmm2ext/keyboard.h>
64 #include "gtkmm2ext/utils.h"
65 #include "gtkmm2ext/window_title.h"
66 #include "gtkmm2ext/choice.h"
67 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
69 #include "ardour/analysis_graph.h"
70 #include "ardour/audio_track.h"
71 #include "ardour/audioengine.h"
72 #include "ardour/audioregion.h"
73 #include "ardour/lmath.h"
74 #include "ardour/location.h"
75 #include "ardour/profile.h"
76 #include "ardour/route.h"
77 #include "ardour/route_group.h"
78 #include "ardour/session_playlists.h"
79 #include "ardour/tempo.h"
80 #include "ardour/utils.h"
81 #include "ardour/vca_manager.h"
82 #include "ardour/vca.h"
84 #include "canvas/debug.h"
85 #include "canvas/text.h"
87 #include "control_protocol/control_protocol.h"
90 #include "analysis_window.h"
91 #include "ardour_spacer.h"
92 #include "audio_clock.h"
93 #include "audio_region_view.h"
94 #include "audio_streamview.h"
95 #include "audio_time_axis.h"
96 #include "automation_time_axis.h"
97 #include "bundle_manager.h"
98 #include "crossfade_edit.h"
102 #include "editor_cursors.h"
103 #include "editor_drag.h"
104 #include "editor_group_tabs.h"
105 #include "editor_locations.h"
106 #include "editor_regions.h"
107 #include "editor_route_groups.h"
108 #include "editor_routes.h"
109 #include "editor_snapshots.h"
110 #include "editor_summary.h"
111 #include "export_report.h"
112 #include "global_port_matrix.h"
113 #include "gui_object.h"
114 #include "gui_thread.h"
115 #include "keyboard.h"
116 #include "luainstance.h"
118 #include "midi_region_view.h"
119 #include "midi_time_axis.h"
120 #include "mixer_strip.h"
121 #include "mixer_ui.h"
122 #include "mouse_cursors.h"
123 #include "note_base.h"
124 #include "playlist_selector.h"
125 #include "public_editor.h"
126 #include "quantize_dialog.h"
127 #include "region_layering_order_editor.h"
128 #include "rgb_macros.h"
129 #include "rhythm_ferret.h"
130 #include "route_sorter.h"
131 #include "selection.h"
132 #include "simple_progress_dialog.h"
134 #include "tempo_lines.h"
135 #include "time_axis_view.h"
136 #include "time_info_box.h"
138 #include "tooltips.h"
139 #include "ui_config.h"
141 #include "vca_time_axis.h"
142 #include "verbose_cursor.h"
144 #include "pbd/i18n.h"
147 using namespace ARDOUR;
148 using namespace ARDOUR_UI_UTILS;
151 using namespace Glib;
152 using namespace Gtkmm2ext;
153 using namespace Editing;
155 using PBD::internationalize;
157 using Gtkmm2ext::Keyboard;
159 double Editor::timebar_height = 15.0;
161 static const gchar *_snap_type_strings[] = {
195 static const gchar *_snap_mode_strings[] = {
202 static const gchar *_edit_point_strings[] = {
209 static const gchar *_edit_mode_strings[] = {
217 static const gchar *_zoom_focus_strings[] = {
227 #ifdef USE_RUBBERBAND
228 static const gchar *_rb_opt_strings[] = {
231 N_("Balanced multitimbral mixture"),
232 N_("Unpitched percussion with stable notes"),
233 N_("Crisp monophonic instrumental"),
234 N_("Unpitched solo percussion"),
235 N_("Resample without preserving pitch"),
240 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
243 : PublicEditor (global_hpacker)
244 , editor_mixer_strip_width (Wide)
245 , constructed (false)
246 , _playlist_selector (0)
248 , no_save_visual (false)
250 , samples_per_pixel (2048)
251 , zoom_focus (ZoomFocusPlayhead)
252 , mouse_mode (MouseObject)
253 , pre_internal_snap_type (SnapToBeat)
254 , pre_internal_snap_mode (SnapOff)
255 , internal_snap_type (SnapToBeat)
256 , internal_snap_mode (SnapOff)
257 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
258 , _notebook_shrunk (false)
259 , location_marker_color (0)
260 , location_range_color (0)
261 , location_loop_color (0)
262 , location_punch_color (0)
263 , location_cd_marker_color (0)
265 , _show_marker_lines (false)
266 , clicked_axisview (0)
267 , clicked_routeview (0)
268 , clicked_regionview (0)
269 , clicked_selection (0)
270 , clicked_control_point (0)
271 , button_release_can_deselect (true)
272 , _mouse_changed_selection (false)
273 , region_edit_menu_split_item (0)
274 , region_edit_menu_split_multichannel_item (0)
275 , track_region_edit_playlist_menu (0)
276 , track_edit_playlist_submenu (0)
277 , track_selection_edit_playlist_submenu (0)
278 , _popup_region_menu_item (0)
280 , _track_canvas_viewport (0)
281 , within_track_canvas (false)
282 , _verbose_cursor (0)
286 , range_marker_group (0)
287 , transport_marker_group (0)
288 , cd_marker_group (0)
289 , _time_markers_group (0)
290 , hv_scroll_group (0)
292 , cursor_scroll_group (0)
293 , no_scroll_group (0)
294 , _trackview_group (0)
295 , _drag_motion_group (0)
296 , _canvas_drop_zone (0)
297 , no_ruler_shown_update (false)
298 , ruler_grabbed_widget (0)
300 , minsec_mark_interval (0)
301 , minsec_mark_modulo (0)
303 , timecode_mark_modulo (0)
304 , timecode_nmarks (0)
305 , _samples_ruler_interval (0)
308 , bbt_bar_helper_on (0)
309 , bbt_accent_modulo (0)
314 , visible_timebars (0)
315 , editor_ruler_menu (0)
319 , range_marker_bar (0)
320 , transport_marker_bar (0)
322 , minsec_label (_("Mins:Secs"))
323 , bbt_label (_("Bars:Beats"))
324 , timecode_label (_("Timecode"))
325 , samples_label (_("Samples"))
326 , tempo_label (_("Tempo"))
327 , meter_label (_("Meter"))
328 , mark_label (_("Location Markers"))
329 , range_mark_label (_("Range Markers"))
330 , transport_mark_label (_("Loop/Punch Ranges"))
331 , cd_mark_label (_("CD Markers"))
332 , videotl_label (_("Video Timeline"))
334 , playhead_cursor (0)
335 , edit_packer (4, 4, true)
336 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
337 , horizontal_adjustment (0.0, 0.0, 1e16)
338 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
339 , controls_layout (unused_adjustment, vertical_adjustment)
340 , _scroll_callbacks (0)
341 , _visible_canvas_width (0)
342 , _visible_canvas_height (0)
343 , _full_canvas_height (0)
344 , edit_controls_left_menu (0)
345 , edit_controls_right_menu (0)
346 , _last_update_time (0)
347 , _err_screen_engine (0)
348 , cut_buffer_start (0)
349 , cut_buffer_length (0)
350 , button_bindings (0)
354 , current_interthread_info (0)
355 , analysis_window (0)
356 , select_new_marker (false)
358 , scrubbing_direction (0)
359 , scrub_reversals (0)
360 , scrub_reverse_distance (0)
361 , have_pending_keyboard_selection (false)
362 , pending_keyboard_selection_start (0)
363 , _snap_type (SnapToBeat)
364 , _snap_mode (SnapOff)
365 , snap_threshold (5.0)
366 , ignore_gui_changes (false)
367 , _drags (new DragManager (this))
369 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
370 , _dragging_playhead (false)
371 , _dragging_edit_point (false)
372 , _show_measures (true)
373 , _follow_playhead (true)
374 , _stationary_playhead (false)
377 , global_rect_group (0)
378 , time_line_group (0)
379 , tempo_marker_menu (0)
380 , meter_marker_menu (0)
382 , range_marker_menu (0)
383 , transport_marker_menu (0)
384 , new_transport_marker_menu (0)
386 , marker_menu_item (0)
387 , bbt_beat_subdivision (4)
388 , _visible_track_count (-1)
389 , toolbar_selection_clock_table (2,3)
390 , automation_mode_button (_("mode"))
391 , selection (new Selection (this))
392 , cut_buffer (new Selection (this))
393 , _selection_memento (new SelectionMemento())
394 , _all_region_actions_sensitized (false)
395 , _ignore_region_action (false)
396 , _last_region_menu_was_main (false)
397 , _track_selection_change_without_scroll (false)
398 , cd_marker_bar_drag_rect (0)
399 , range_bar_drag_rect (0)
400 , transport_bar_drag_rect (0)
401 , transport_bar_range_rect (0)
402 , transport_bar_preroll_rect (0)
403 , transport_bar_postroll_rect (0)
404 , transport_loop_range_rect (0)
405 , transport_punch_range_rect (0)
406 , transport_punchin_line (0)
407 , transport_punchout_line (0)
408 , transport_preroll_rect (0)
409 , transport_postroll_rect (0)
411 , rubberband_rect (0)
417 , autoscroll_horizontal_allowed (false)
418 , autoscroll_vertical_allowed (false)
420 , autoscroll_widget (0)
421 , show_gain_after_trim (false)
422 , selection_op_cmd_depth (0)
423 , selection_op_history_it (0)
424 , no_save_instant (false)
426 , current_mixer_strip (0)
427 , show_editor_mixer_when_tracks_arrive (false)
428 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
429 , current_stepping_trackview (0)
430 , last_track_height_step_timestamp (0)
432 , entered_regionview (0)
433 , clear_entered_track (false)
434 , _edit_point (EditAtMouse)
435 , meters_running (false)
437 , _have_idled (false)
438 , resize_idle_id (-1)
439 , _pending_resize_amount (0)
440 , _pending_resize_view (0)
441 , _pending_locate_request (false)
442 , _pending_initial_locate (false)
446 , layering_order_editor (0)
447 , _last_cut_copy_source_track (0)
448 , _region_selection_change_updates_region_list (true)
450 , _following_mixer_selection (false)
451 , _control_point_toggled_on_press (false)
452 , _stepping_axis_view (0)
453 , quantize_dialog (0)
454 , _main_menu_disabler (0)
455 , myactions (X_("editor"))
457 /* we are a singleton */
459 PublicEditor::_instance = this;
463 last_event_time.tv_sec = 0;
464 last_event_time.tv_usec = 0;
466 selection_op_history.clear();
469 snap_type_strings = I18N (_snap_type_strings);
470 snap_mode_strings = I18N (_snap_mode_strings);
471 zoom_focus_strings = I18N (_zoom_focus_strings);
472 edit_mode_strings = I18N (_edit_mode_strings);
473 edit_point_strings = I18N (_edit_point_strings);
474 #ifdef USE_RUBBERBAND
475 rb_opt_strings = I18N (_rb_opt_strings);
479 build_edit_mode_menu();
480 build_zoom_focus_menu();
481 build_track_count_menu();
482 build_snap_mode_menu();
483 build_snap_type_menu();
484 build_edit_point_menu();
486 location_marker_color = UIConfiguration::instance().color ("location marker");
487 location_range_color = UIConfiguration::instance().color ("location range");
488 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
489 location_loop_color = UIConfiguration::instance().color ("location loop");
490 location_punch_color = UIConfiguration::instance().color ("location punch");
492 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
494 TimeAxisView::setup_sizes ();
495 ArdourMarker::setup_sizes (timebar_height);
496 TempoCurve::setup_sizes (timebar_height);
498 bbt_label.set_name ("EditorRulerLabel");
499 bbt_label.set_size_request (-1, (int)timebar_height);
500 bbt_label.set_alignment (1.0, 0.5);
501 bbt_label.set_padding (5,0);
503 bbt_label.set_no_show_all();
504 minsec_label.set_name ("EditorRulerLabel");
505 minsec_label.set_size_request (-1, (int)timebar_height);
506 minsec_label.set_alignment (1.0, 0.5);
507 minsec_label.set_padding (5,0);
508 minsec_label.hide ();
509 minsec_label.set_no_show_all();
510 timecode_label.set_name ("EditorRulerLabel");
511 timecode_label.set_size_request (-1, (int)timebar_height);
512 timecode_label.set_alignment (1.0, 0.5);
513 timecode_label.set_padding (5,0);
514 timecode_label.hide ();
515 timecode_label.set_no_show_all();
516 samples_label.set_name ("EditorRulerLabel");
517 samples_label.set_size_request (-1, (int)timebar_height);
518 samples_label.set_alignment (1.0, 0.5);
519 samples_label.set_padding (5,0);
520 samples_label.hide ();
521 samples_label.set_no_show_all();
523 tempo_label.set_name ("EditorRulerLabel");
524 tempo_label.set_size_request (-1, (int)timebar_height);
525 tempo_label.set_alignment (1.0, 0.5);
526 tempo_label.set_padding (5,0);
528 tempo_label.set_no_show_all();
530 meter_label.set_name ("EditorRulerLabel");
531 meter_label.set_size_request (-1, (int)timebar_height);
532 meter_label.set_alignment (1.0, 0.5);
533 meter_label.set_padding (5,0);
535 meter_label.set_no_show_all();
537 if (Profile->get_trx()) {
538 mark_label.set_text (_("Markers"));
540 mark_label.set_name ("EditorRulerLabel");
541 mark_label.set_size_request (-1, (int)timebar_height);
542 mark_label.set_alignment (1.0, 0.5);
543 mark_label.set_padding (5,0);
545 mark_label.set_no_show_all();
547 cd_mark_label.set_name ("EditorRulerLabel");
548 cd_mark_label.set_size_request (-1, (int)timebar_height);
549 cd_mark_label.set_alignment (1.0, 0.5);
550 cd_mark_label.set_padding (5,0);
551 cd_mark_label.hide();
552 cd_mark_label.set_no_show_all();
554 videotl_bar_height = 4;
555 videotl_label.set_name ("EditorRulerLabel");
556 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
557 videotl_label.set_alignment (1.0, 0.5);
558 videotl_label.set_padding (5,0);
559 videotl_label.hide();
560 videotl_label.set_no_show_all();
562 range_mark_label.set_name ("EditorRulerLabel");
563 range_mark_label.set_size_request (-1, (int)timebar_height);
564 range_mark_label.set_alignment (1.0, 0.5);
565 range_mark_label.set_padding (5,0);
566 range_mark_label.hide();
567 range_mark_label.set_no_show_all();
569 transport_mark_label.set_name ("EditorRulerLabel");
570 transport_mark_label.set_size_request (-1, (int)timebar_height);
571 transport_mark_label.set_alignment (1.0, 0.5);
572 transport_mark_label.set_padding (5,0);
573 transport_mark_label.hide();
574 transport_mark_label.set_no_show_all();
576 initialize_canvas ();
578 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
580 _summary = new EditorSummary (this);
582 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
584 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
586 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
587 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
589 edit_controls_vbox.set_spacing (0);
590 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
591 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
593 HBox* h = manage (new HBox);
594 _group_tabs = new EditorGroupTabs (this);
595 if (!ARDOUR::Profile->get_trx()) {
596 h->pack_start (*_group_tabs, PACK_SHRINK);
598 h->pack_start (edit_controls_vbox);
599 controls_layout.add (*h);
601 controls_layout.set_name ("EditControlsBase");
602 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
603 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
604 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
606 _cursors = new MouseCursors;
607 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
608 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
610 /* Push default cursor to ever-present bottom of cursor stack. */
611 push_canvas_cursor(_cursors->grabber);
613 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
615 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
616 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
617 pad_line_1->set_outline_color (0xFF0000FF);
623 edit_packer.set_col_spacings (0);
624 edit_packer.set_row_spacings (0);
625 edit_packer.set_homogeneous (false);
626 edit_packer.set_border_width (0);
627 edit_packer.set_name ("EditorWindow");
629 time_bars_event_box.add (time_bars_vbox);
630 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
631 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
633 /* labels for the time bars */
634 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
636 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
638 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
640 bottom_hbox.set_border_width (2);
641 bottom_hbox.set_spacing (3);
643 _route_groups = new EditorRouteGroups (this);
644 _routes = new EditorRoutes (this);
645 _regions = new EditorRegions (this);
646 _snapshots = new EditorSnapshots (this);
647 _locations = new EditorLocations (this);
648 _time_info_box = new TimeInfoBox ("EditorTimeInfo", true);
650 /* these are static location signals */
652 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
653 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
654 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
656 add_notebook_page (_("Regions"), _regions->widget ());
657 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
658 add_notebook_page (_("Snapshots"), _snapshots->widget ());
659 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
660 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
662 _the_notebook.set_show_tabs (true);
663 _the_notebook.set_scrollable (true);
664 _the_notebook.popup_disable ();
665 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
666 _the_notebook.show_all ();
668 _notebook_shrunk = false;
671 /* Pick up some settings we need to cache, early */
673 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
676 if (settings && (prop = settings->property ("notebook-shrunk"))) {
677 _notebook_shrunk = string_is_affirmative (prop->value ());
680 editor_summary_pane.set_check_divider_position (true);
681 editor_summary_pane.add (edit_packer);
683 Button* summary_arrows_left_left = manage (new Button);
684 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
685 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
686 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
688 Button* summary_arrows_left_right = manage (new Button);
689 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
690 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
691 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
693 VBox* summary_arrows_left = manage (new VBox);
694 summary_arrows_left->pack_start (*summary_arrows_left_left);
695 summary_arrows_left->pack_start (*summary_arrows_left_right);
697 Button* summary_arrows_right_up = manage (new Button);
698 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
699 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
700 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
702 Button* summary_arrows_right_down = manage (new Button);
703 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
704 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
705 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
707 VBox* summary_arrows_right = manage (new VBox);
708 summary_arrows_right->pack_start (*summary_arrows_right_up);
709 summary_arrows_right->pack_start (*summary_arrows_right_down);
711 Frame* summary_frame = manage (new Frame);
712 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
714 summary_frame->add (*_summary);
715 summary_frame->show ();
717 _summary_hbox.pack_start (*summary_arrows_left, false, false);
718 _summary_hbox.pack_start (*summary_frame, true, true);
719 _summary_hbox.pack_start (*summary_arrows_right, false, false);
721 if (!ARDOUR::Profile->get_trx()) {
722 editor_summary_pane.add (_summary_hbox);
725 edit_pane.set_check_divider_position (true);
726 edit_pane.add (editor_summary_pane);
727 if (!ARDOUR::Profile->get_trx()) {
728 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
729 _editor_list_vbox.pack_start (_the_notebook);
730 edit_pane.add (_editor_list_vbox);
731 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
734 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
735 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
742 if (!settings || ((prop = settings->property ("edit-horizontal-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
743 /* initial allocation is 90% to canvas, 10% to notebook */
744 edit_pane.set_divider (0, 0.90);
746 edit_pane.set_divider (0, fract);
749 if (!settings || ((prop = settings->property ("edit-vertical-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
750 /* initial allocation is 90% to canvas, 10% to summary */
751 editor_summary_pane.set_divider (0, 0.90);
754 editor_summary_pane.set_divider (0, fract);
758 global_vpacker.set_spacing (2);
759 global_vpacker.set_border_width (0);
761 //the next three EventBoxes provide the ability for their child widgets to have a background color. That is all.
763 Gtk::EventBox* ebox = manage (new Gtk::EventBox); //a themeable box
764 ebox->set_name("EditorWindow");
765 ebox->add (toolbar_hbox);
767 Gtk::EventBox* epane_box = manage (new Gtkmm2ext::EventBoxExt); //a themeable box
768 epane_box->set_name("EditorWindow");
769 epane_box->add (edit_pane);
771 Gtk::EventBox* epane_box2 = manage (new Gtkmm2ext::EventBoxExt); //a themeable box
772 epane_box2->set_name("EditorWindow");
773 epane_box2->add (global_vpacker);
775 global_vpacker.pack_start (*ebox, false, false);
776 global_vpacker.pack_start (*epane_box, true, true);
777 global_hpacker.pack_start (*epane_box2, true, true);
779 /* need to show the "contents" widget so that notebook will show if tab is switched to
782 global_hpacker.show ();
784 /* register actions now so that set_state() can find them and set toggles/checks etc */
791 _playlist_selector = new PlaylistSelector();
792 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
794 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
798 nudge_forward_button.set_name ("nudge button");
799 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
801 nudge_backward_button.set_name ("nudge button");
802 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
804 fade_context_menu.set_name ("ArdourContextMenu");
806 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
808 /* allow external control surfaces/protocols to do various things */
810 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
811 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
812 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
813 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
814 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
815 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
816 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
817 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
818 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
819 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
820 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
821 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
822 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
823 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
825 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
826 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
827 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
828 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
829 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
831 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
835 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
837 /* problematic: has to return a value and thus cannot be x-thread */
839 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
841 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
842 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
844 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
846 _ignore_region_action = false;
847 _last_region_menu_was_main = false;
848 _popup_region_menu_item = 0;
850 _show_marker_lines = false;
852 /* Button bindings */
854 button_bindings = new Bindings ("editor-mouse");
856 XMLNode* node = button_settings();
858 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
859 button_bindings->load_operation (**i);
865 /* grab current parameter state */
866 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
867 UIConfiguration::instance().map_parameters (pc);
869 setup_fade_images ();
876 delete button_bindings;
878 delete _route_groups;
879 delete _track_canvas_viewport;
882 delete _verbose_cursor;
883 delete quantize_dialog;
889 delete _playlist_selector;
890 delete _time_info_box;
895 LuaInstance::destroy_instance ();
897 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
900 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_in_images.begin(); i != _xfade_in_images.end (); ++i) {
903 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_out_images.begin(); i != _xfade_out_images.end (); ++i) {
909 Editor::button_settings () const
911 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
912 XMLNode* node = find_named_node (*settings, X_("Buttons"));
915 node = new XMLNode (X_("Buttons"));
922 Editor::get_smart_mode () const
924 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
928 Editor::catch_vanishing_regionview (RegionView *rv)
930 /* note: the selection will take care of the vanishing
931 audioregionview by itself.
934 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
938 if (clicked_regionview == rv) {
939 clicked_regionview = 0;
942 if (entered_regionview == rv) {
943 set_entered_regionview (0);
946 if (!_all_region_actions_sensitized) {
947 sensitize_all_region_actions (true);
952 Editor::set_entered_regionview (RegionView* rv)
954 if (rv == entered_regionview) {
958 if (entered_regionview) {
959 entered_regionview->exited ();
962 entered_regionview = rv;
964 if (entered_regionview != 0) {
965 entered_regionview->entered ();
968 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
969 /* This RegionView entry might have changed what region actions
970 are allowed, so sensitize them all in case a key is pressed.
972 sensitize_all_region_actions (true);
977 Editor::set_entered_track (TimeAxisView* tav)
980 entered_track->exited ();
986 entered_track->entered ();
991 Editor::instant_save ()
993 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
998 _session->add_instant_xml(get_state());
1000 Config->add_instant_xml(get_state());
1005 Editor::control_vertical_zoom_in_all ()
1007 tav_zoom_smooth (false, true);
1011 Editor::control_vertical_zoom_out_all ()
1013 tav_zoom_smooth (true, true);
1017 Editor::control_vertical_zoom_in_selected ()
1019 tav_zoom_smooth (false, false);
1023 Editor::control_vertical_zoom_out_selected ()
1025 tav_zoom_smooth (true, false);
1029 Editor::control_view (uint32_t view)
1031 goto_visual_state (view);
1035 Editor::control_unselect ()
1037 selection->clear_tracks ();
1041 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1043 TimeAxisView* tav = axis_view_from_stripable (s);
1047 case Selection::Add:
1048 selection->add (tav);
1050 case Selection::Toggle:
1051 selection->toggle (tav);
1053 case Selection::Extend:
1055 case Selection::Set:
1056 selection->set (tav);
1060 selection->clear_tracks ();
1065 Editor::control_step_tracks_up ()
1067 scroll_tracks_up_line ();
1071 Editor::control_step_tracks_down ()
1073 scroll_tracks_down_line ();
1077 Editor::control_scroll (float fraction)
1079 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1085 double step = fraction * current_page_samples();
1088 _control_scroll_target is an optional<T>
1090 it acts like a pointer to an framepos_t, with
1091 a operator conversion to boolean to check
1092 that it has a value could possibly use
1093 playhead_cursor->current_frame to store the
1094 value and a boolean in the class to know
1095 when it's out of date
1098 if (!_control_scroll_target) {
1099 _control_scroll_target = _session->transport_frame();
1100 _dragging_playhead = true;
1103 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1104 *_control_scroll_target = 0;
1105 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1106 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1108 *_control_scroll_target += (framepos_t) trunc (step);
1111 /* move visuals, we'll catch up with it later */
1113 playhead_cursor->set_position (*_control_scroll_target);
1114 UpdateAllTransportClocks (*_control_scroll_target);
1116 if (*_control_scroll_target > (current_page_samples() / 2)) {
1117 /* try to center PH in window */
1118 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1124 Now we do a timeout to actually bring the session to the right place
1125 according to the playhead. This is to avoid reading disk buffers on every
1126 call to control_scroll, which is driven by ScrollTimeline and therefore
1127 probably by a control surface wheel which can generate lots of events.
1129 /* cancel the existing timeout */
1131 control_scroll_connection.disconnect ();
1133 /* add the next timeout */
1135 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1139 Editor::deferred_control_scroll (framepos_t /*target*/)
1141 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1142 // reset for next stream
1143 _control_scroll_target = boost::none;
1144 _dragging_playhead = false;
1149 Editor::access_action (std::string action_group, std::string action_item)
1155 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1158 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1166 Editor::on_realize ()
1170 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1171 start_lock_event_timing ();
1176 Editor::start_lock_event_timing ()
1178 /* check if we should lock the GUI every 30 seconds */
1180 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1184 Editor::generic_event_handler (GdkEvent* ev)
1187 case GDK_BUTTON_PRESS:
1188 case GDK_BUTTON_RELEASE:
1189 case GDK_MOTION_NOTIFY:
1191 case GDK_KEY_RELEASE:
1192 if (contents().is_mapped()) {
1193 gettimeofday (&last_event_time, 0);
1197 case GDK_LEAVE_NOTIFY:
1198 switch (ev->crossing.detail) {
1199 case GDK_NOTIFY_UNKNOWN:
1200 case GDK_NOTIFY_INFERIOR:
1201 case GDK_NOTIFY_ANCESTOR:
1203 case GDK_NOTIFY_VIRTUAL:
1204 case GDK_NOTIFY_NONLINEAR:
1205 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1206 /* leaving window, so reset focus, thus ending any and
1207 all text entry operations.
1209 ARDOUR_UI::instance()->reset_focus (&contents());
1222 Editor::lock_timeout_callback ()
1224 struct timeval now, delta;
1226 gettimeofday (&now, 0);
1228 timersub (&now, &last_event_time, &delta);
1230 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1232 /* don't call again. Returning false will effectively
1233 disconnect us from the timer callback.
1235 unlock() will call start_lock_event_timing() to get things
1245 Editor::map_position_change (framepos_t frame)
1247 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1249 if (_session == 0) {
1253 if (_follow_playhead) {
1254 center_screen (frame);
1257 playhead_cursor->set_position (frame);
1261 Editor::center_screen (framepos_t frame)
1263 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1265 /* if we're off the page, then scroll.
1268 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1269 center_screen_internal (frame, page);
1274 Editor::center_screen_internal (framepos_t frame, float page)
1279 frame -= (framepos_t) page;
1284 reset_x_origin (frame);
1289 Editor::update_title ()
1291 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1293 if (!own_window()) {
1298 bool dirty = _session->dirty();
1300 string session_name;
1302 if (_session->snap_name() != _session->name()) {
1303 session_name = _session->snap_name();
1305 session_name = _session->name();
1309 session_name = "*" + session_name;
1312 WindowTitle title(session_name);
1313 title += S_("Window|Editor");
1314 title += Glib::get_application_name();
1315 own_window()->set_title (title.get_string());
1317 /* ::session_going_away() will have taken care of it */
1322 Editor::set_session (Session *t)
1324 SessionHandlePtr::set_session (t);
1330 _playlist_selector->set_session (_session);
1331 nudge_clock->set_session (_session);
1332 _summary->set_session (_session);
1333 _group_tabs->set_session (_session);
1334 _route_groups->set_session (_session);
1335 _regions->set_session (_session);
1336 _snapshots->set_session (_session);
1337 _routes->set_session (_session);
1338 _locations->set_session (_session);
1339 _time_info_box->set_session (_session);
1341 if (rhythm_ferret) {
1342 rhythm_ferret->set_session (_session);
1345 if (analysis_window) {
1346 analysis_window->set_session (_session);
1350 sfbrowser->set_session (_session);
1353 compute_fixed_ruler_scale ();
1355 /* Make sure we have auto loop and auto punch ranges */
1357 Location* loc = _session->locations()->auto_loop_location();
1359 loc->set_name (_("Loop"));
1362 loc = _session->locations()->auto_punch_location();
1365 loc->set_name (_("Punch"));
1368 refresh_location_display ();
1370 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1371 the selected Marker; this needs the LocationMarker list to be available.
1373 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1374 set_state (*node, Stateful::loading_state_version);
1376 /* catch up with the playhead */
1378 _session->request_locate (playhead_cursor->current_frame ());
1379 _pending_initial_locate = true;
1383 /* These signals can all be emitted by a non-GUI thread. Therefore the
1384 handlers for them must not attempt to directly interact with the GUI,
1385 but use PBD::Signal<T>::connect() which accepts an event loop
1386 ("context") where the handler will be asked to run.
1389 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1390 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1391 _session->TransportLooped.connect (_session_connections, invalidator (*this), boost::bind (&Editor::transport_looped, this), gui_context());
1392 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1393 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1394 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1395 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1396 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1397 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1398 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1399 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1400 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1401 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1402 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1403 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1404 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1406 playhead_cursor->show ();
1408 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1409 Config->map_parameters (pc);
1410 _session->config.map_parameters (pc);
1412 restore_ruler_visibility ();
1413 //tempo_map_changed (PropertyChange (0));
1414 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1416 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1417 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1420 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1421 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1424 switch (_snap_type) {
1425 case SnapToRegionStart:
1426 case SnapToRegionEnd:
1427 case SnapToRegionSync:
1428 case SnapToRegionBoundary:
1429 build_region_boundary_cache ();
1436 /* catch up on selection of stripables (other selection state is lost
1437 * when a session is closed
1442 _session->get_stripables (sl);
1443 for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
1444 if ((*s)->presentation_info().selected()) {
1445 RouteTimeAxisView* rtav = get_route_view_by_route_id ((*s)->id());
1447 tl.push_back (rtav);
1452 selection->set (tl);
1455 /* register for undo history */
1456 _session->register_with_memento_command_factory(id(), this);
1457 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1459 LuaInstance::instance()->set_session(_session);
1461 start_updating_meters ();
1465 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1467 using namespace Menu_Helpers;
1469 void (Editor::*emf)(FadeShape);
1470 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1473 images = &_xfade_in_images;
1474 emf = &Editor::set_fade_in_shape;
1476 images = &_xfade_out_images;
1477 emf = &Editor::set_fade_out_shape;
1482 _("Linear (for highly correlated material)"),
1483 *(*images)[FadeLinear],
1484 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1488 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1492 _("Constant power"),
1493 *(*images)[FadeConstantPower],
1494 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1497 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1502 *(*images)[FadeSymmetric],
1503 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1507 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1512 *(*images)[FadeSlow],
1513 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1516 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1521 *(*images)[FadeFast],
1522 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1525 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1528 /** Pop up a context menu for when the user clicks on a start crossfade */
1530 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1532 using namespace Menu_Helpers;
1533 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1538 MenuList& items (xfade_in_context_menu.items());
1541 if (arv->audio_region()->fade_in_active()) {
1542 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1544 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1547 items.push_back (SeparatorElem());
1548 fill_xfade_menu (items, true);
1550 xfade_in_context_menu.popup (button, time);
1553 /** Pop up a context menu for when the user clicks on an end crossfade */
1555 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1557 using namespace Menu_Helpers;
1558 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1563 MenuList& items (xfade_out_context_menu.items());
1566 if (arv->audio_region()->fade_out_active()) {
1567 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1569 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1572 items.push_back (SeparatorElem());
1573 fill_xfade_menu (items, false);
1575 xfade_out_context_menu.popup (button, time);
1579 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1581 using namespace Menu_Helpers;
1582 Menu* (Editor::*build_menu_function)();
1585 switch (item_type) {
1587 case RegionViewName:
1588 case RegionViewNameHighlight:
1589 case LeftFrameHandle:
1590 case RightFrameHandle:
1591 if (with_selection) {
1592 build_menu_function = &Editor::build_track_selection_context_menu;
1594 build_menu_function = &Editor::build_track_region_context_menu;
1599 if (with_selection) {
1600 build_menu_function = &Editor::build_track_selection_context_menu;
1602 build_menu_function = &Editor::build_track_context_menu;
1607 if (clicked_routeview->track()) {
1608 build_menu_function = &Editor::build_track_context_menu;
1610 build_menu_function = &Editor::build_track_bus_context_menu;
1615 /* probably shouldn't happen but if it does, we don't care */
1619 menu = (this->*build_menu_function)();
1620 menu->set_name ("ArdourContextMenu");
1622 /* now handle specific situations */
1624 switch (item_type) {
1626 case RegionViewName:
1627 case RegionViewNameHighlight:
1628 case LeftFrameHandle:
1629 case RightFrameHandle:
1630 if (!with_selection) {
1631 if (region_edit_menu_split_item) {
1632 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1633 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1635 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1638 if (region_edit_menu_split_multichannel_item) {
1639 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1640 region_edit_menu_split_multichannel_item->set_sensitive (true);
1642 region_edit_menu_split_multichannel_item->set_sensitive (false);
1655 /* probably shouldn't happen but if it does, we don't care */
1659 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1661 /* Bounce to disk */
1663 using namespace Menu_Helpers;
1664 MenuList& edit_items = menu->items();
1666 edit_items.push_back (SeparatorElem());
1668 switch (clicked_routeview->audio_track()->freeze_state()) {
1669 case AudioTrack::NoFreeze:
1670 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1673 case AudioTrack::Frozen:
1674 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1677 case AudioTrack::UnFrozen:
1678 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1684 if (item_type == StreamItem && clicked_routeview) {
1685 clicked_routeview->build_underlay_menu(menu);
1688 /* When the region menu is opened, we setup the actions so that they look right
1691 sensitize_the_right_region_actions (false);
1692 _last_region_menu_was_main = false;
1694 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1695 menu->popup (button, time);
1699 Editor::build_track_context_menu ()
1701 using namespace Menu_Helpers;
1703 MenuList& edit_items = track_context_menu.items();
1706 add_dstream_context_items (edit_items);
1707 return &track_context_menu;
1711 Editor::build_track_bus_context_menu ()
1713 using namespace Menu_Helpers;
1715 MenuList& edit_items = track_context_menu.items();
1718 add_bus_context_items (edit_items);
1719 return &track_context_menu;
1723 Editor::build_track_region_context_menu ()
1725 using namespace Menu_Helpers;
1726 MenuList& edit_items = track_region_context_menu.items();
1729 /* we've just cleared the track region context menu, so the menu that these
1730 two items were on will have disappeared; stop them dangling.
1732 region_edit_menu_split_item = 0;
1733 region_edit_menu_split_multichannel_item = 0;
1735 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1738 boost::shared_ptr<Track> tr;
1739 boost::shared_ptr<Playlist> pl;
1741 if ((tr = rtv->track())) {
1742 add_region_context_items (edit_items, tr);
1746 add_dstream_context_items (edit_items);
1748 return &track_region_context_menu;
1752 Editor::loudness_analyze_region_selection ()
1757 Selection& s (PublicEditor::instance ().get_selection ());
1758 RegionSelection ars = s.regions;
1759 ARDOUR::AnalysisGraph ag (_session);
1760 framecnt_t total_work = 0;
1762 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1763 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1767 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1770 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1771 total_work += arv->region ()->length ();
1774 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1776 ag.set_total_frames (total_work);
1777 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1780 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1781 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1785 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1789 ag.analyze_region (ar);
1792 if (!ag.canceled ()) {
1793 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1799 Editor::loudness_analyze_range_selection ()
1804 Selection& s (PublicEditor::instance ().get_selection ());
1805 TimeSelection ts = s.time;
1806 ARDOUR::AnalysisGraph ag (_session);
1807 framecnt_t total_work = 0;
1809 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1810 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1814 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1818 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1819 total_work += j->length ();
1823 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1825 ag.set_total_frames (total_work);
1826 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1829 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1830 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1834 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1838 ag.analyze_range (rui->route (), pl, ts);
1841 if (!ag.canceled ()) {
1842 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1848 Editor::spectral_analyze_region_selection ()
1850 if (analysis_window == 0) {
1851 analysis_window = new AnalysisWindow();
1854 analysis_window->set_session(_session);
1856 analysis_window->show_all();
1859 analysis_window->set_regionmode();
1860 analysis_window->analyze();
1862 analysis_window->present();
1866 Editor::spectral_analyze_range_selection()
1868 if (analysis_window == 0) {
1869 analysis_window = new AnalysisWindow();
1872 analysis_window->set_session(_session);
1874 analysis_window->show_all();
1877 analysis_window->set_rangemode();
1878 analysis_window->analyze();
1880 analysis_window->present();
1884 Editor::build_track_selection_context_menu ()
1886 using namespace Menu_Helpers;
1887 MenuList& edit_items = track_selection_context_menu.items();
1888 edit_items.clear ();
1890 add_selection_context_items (edit_items);
1891 // edit_items.push_back (SeparatorElem());
1892 // add_dstream_context_items (edit_items);
1894 return &track_selection_context_menu;
1898 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1900 using namespace Menu_Helpers;
1902 /* OK, stick the region submenu at the top of the list, and then add
1906 RegionSelection rs = get_regions_from_selection_and_entered ();
1908 string::size_type pos = 0;
1909 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1911 /* we have to hack up the region name because "_" has a special
1912 meaning for menu titles.
1915 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1916 menu_item_name.replace (pos, 1, "__");
1920 if (_popup_region_menu_item == 0) {
1921 _popup_region_menu_item = new MenuItem (menu_item_name);
1922 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1923 _popup_region_menu_item->show ();
1925 _popup_region_menu_item->set_label (menu_item_name);
1928 /* No layering allowed in later is higher layering model */
1929 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1930 if (act && Config->get_layer_model() == LaterHigher) {
1931 act->set_sensitive (false);
1933 act->set_sensitive (true);
1936 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1938 edit_items.push_back (*_popup_region_menu_item);
1939 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1940 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1942 edit_items.push_back (SeparatorElem());
1945 /** Add context menu items relevant to selection ranges.
1946 * @param edit_items List to add the items to.
1949 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1951 using namespace Menu_Helpers;
1953 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1954 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1956 edit_items.push_back (SeparatorElem());
1957 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1959 edit_items.push_back (SeparatorElem());
1960 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1961 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1963 edit_items.push_back (SeparatorElem());
1965 edit_items.push_back (
1967 _("Move Range Start to Previous Region Boundary"),
1968 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1972 edit_items.push_back (
1974 _("Move Range Start to Next Region Boundary"),
1975 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1979 edit_items.push_back (
1981 _("Move Range End to Previous Region Boundary"),
1982 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1986 edit_items.push_back (
1988 _("Move Range End to Next Region Boundary"),
1989 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1993 edit_items.push_back (SeparatorElem());
1994 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1995 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1997 edit_items.push_back (SeparatorElem());
1998 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
2000 edit_items.push_back (SeparatorElem());
2001 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
2002 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
2003 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
2005 edit_items.push_back (SeparatorElem());
2006 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
2008 edit_items.push_back (SeparatorElem());
2009 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
2010 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
2012 edit_items.push_back (SeparatorElem());
2013 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
2014 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
2015 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
2016 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
2017 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
2018 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
2019 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2025 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2027 using namespace Menu_Helpers;
2031 Menu *play_menu = manage (new Menu);
2032 MenuList& play_items = play_menu->items();
2033 play_menu->set_name ("ArdourContextMenu");
2035 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2036 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2037 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2038 play_items.push_back (SeparatorElem());
2039 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2041 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2045 Menu *select_menu = manage (new Menu);
2046 MenuList& select_items = select_menu->items();
2047 select_menu->set_name ("ArdourContextMenu");
2049 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2050 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2051 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2052 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2053 select_items.push_back (SeparatorElem());
2054 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2055 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2056 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2057 select_items.push_back (SeparatorElem());
2058 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2059 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2060 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2061 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2062 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2063 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2064 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2066 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2070 Menu *cutnpaste_menu = manage (new Menu);
2071 MenuList& cutnpaste_items = cutnpaste_menu->items();
2072 cutnpaste_menu->set_name ("ArdourContextMenu");
2074 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2075 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2076 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2078 cutnpaste_items.push_back (SeparatorElem());
2080 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2081 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2083 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2085 /* Adding new material */
2087 edit_items.push_back (SeparatorElem());
2088 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2089 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2093 Menu *nudge_menu = manage (new Menu());
2094 MenuList& nudge_items = nudge_menu->items();
2095 nudge_menu->set_name ("ArdourContextMenu");
2097 edit_items.push_back (SeparatorElem());
2098 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2099 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2100 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2101 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2103 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2107 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2109 using namespace Menu_Helpers;
2113 Menu *play_menu = manage (new Menu);
2114 MenuList& play_items = play_menu->items();
2115 play_menu->set_name ("ArdourContextMenu");
2117 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2118 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2119 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2123 Menu *select_menu = manage (new Menu);
2124 MenuList& select_items = select_menu->items();
2125 select_menu->set_name ("ArdourContextMenu");
2127 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2128 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2129 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2130 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2131 select_items.push_back (SeparatorElem());
2132 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2133 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2134 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2135 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2137 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2141 Menu *cutnpaste_menu = manage (new Menu);
2142 MenuList& cutnpaste_items = cutnpaste_menu->items();
2143 cutnpaste_menu->set_name ("ArdourContextMenu");
2145 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2146 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2147 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2149 Menu *nudge_menu = manage (new Menu());
2150 MenuList& nudge_items = nudge_menu->items();
2151 nudge_menu->set_name ("ArdourContextMenu");
2153 edit_items.push_back (SeparatorElem());
2154 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2155 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2156 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2157 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2159 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2163 Editor::snap_type() const
2169 Editor::snap_musical() const
2171 switch (_snap_type) {
2172 case SnapToBeatDiv128:
2173 case SnapToBeatDiv64:
2174 case SnapToBeatDiv32:
2175 case SnapToBeatDiv28:
2176 case SnapToBeatDiv24:
2177 case SnapToBeatDiv20:
2178 case SnapToBeatDiv16:
2179 case SnapToBeatDiv14:
2180 case SnapToBeatDiv12:
2181 case SnapToBeatDiv10:
2182 case SnapToBeatDiv8:
2183 case SnapToBeatDiv7:
2184 case SnapToBeatDiv6:
2185 case SnapToBeatDiv5:
2186 case SnapToBeatDiv4:
2187 case SnapToBeatDiv3:
2188 case SnapToBeatDiv2:
2200 Editor::snap_mode() const
2206 Editor::set_snap_to (SnapType st)
2208 unsigned int snap_ind = (unsigned int)st;
2210 if (internal_editing()) {
2211 internal_snap_type = st;
2213 pre_internal_snap_type = st;
2218 if (snap_ind > snap_type_strings.size() - 1) {
2220 _snap_type = (SnapType)snap_ind;
2223 string str = snap_type_strings[snap_ind];
2225 if (str != snap_type_selector.get_text()) {
2226 snap_type_selector.set_text (str);
2231 switch (_snap_type) {
2232 case SnapToBeatDiv128:
2233 case SnapToBeatDiv64:
2234 case SnapToBeatDiv32:
2235 case SnapToBeatDiv28:
2236 case SnapToBeatDiv24:
2237 case SnapToBeatDiv20:
2238 case SnapToBeatDiv16:
2239 case SnapToBeatDiv14:
2240 case SnapToBeatDiv12:
2241 case SnapToBeatDiv10:
2242 case SnapToBeatDiv8:
2243 case SnapToBeatDiv7:
2244 case SnapToBeatDiv6:
2245 case SnapToBeatDiv5:
2246 case SnapToBeatDiv4:
2247 case SnapToBeatDiv3:
2248 case SnapToBeatDiv2: {
2249 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
2250 update_tempo_based_rulers ();
2254 case SnapToRegionStart:
2255 case SnapToRegionEnd:
2256 case SnapToRegionSync:
2257 case SnapToRegionBoundary:
2258 build_region_boundary_cache ();
2266 redisplay_tempo (false);
2268 SnapChanged (); /* EMIT SIGNAL */
2272 Editor::set_snap_mode (SnapMode mode)
2274 string str = snap_mode_strings[(int)mode];
2276 if (internal_editing()) {
2277 internal_snap_mode = mode;
2279 pre_internal_snap_mode = mode;
2284 if (str != snap_mode_selector.get_text ()) {
2285 snap_mode_selector.set_text (str);
2292 Editor::set_edit_point_preference (EditPoint ep, bool force)
2294 bool changed = (_edit_point != ep);
2297 if (Profile->get_mixbus())
2298 if (ep == EditAtSelectedMarker)
2299 ep = EditAtPlayhead;
2301 string str = edit_point_strings[(int)ep];
2302 if (str != edit_point_selector.get_text ()) {
2303 edit_point_selector.set_text (str);
2306 update_all_enter_cursors();
2308 if (!force && !changed) {
2312 const char* action=NULL;
2314 switch (_edit_point) {
2315 case EditAtPlayhead:
2316 action = "edit-at-playhead";
2318 case EditAtSelectedMarker:
2319 action = "edit-at-marker";
2322 action = "edit-at-mouse";
2326 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2328 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2332 bool in_track_canvas;
2334 if (!mouse_frame (foo, in_track_canvas)) {
2335 in_track_canvas = false;
2338 reset_canvas_action_sensitivity (in_track_canvas);
2339 sensitize_the_right_region_actions (false);
2345 Editor::set_state (const XMLNode& node, int version)
2347 XMLProperty const * prop;
2349 PBD::Unwinder<bool> nsi (no_save_instant, true);
2352 Tabbable::set_state (node, version);
2354 if (_session && (prop = node.property ("playhead"))) {
2356 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2358 playhead_cursor->set_position (pos);
2360 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2361 playhead_cursor->set_position (0);
2364 playhead_cursor->set_position (0);
2367 if ((prop = node.property ("mixer-width"))) {
2368 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2371 if ((prop = node.property ("zoom-focus"))) {
2372 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2374 zoom_focus_selection_done (zoom_focus);
2377 if ((prop = node.property ("zoom"))) {
2378 /* older versions of ardour used floating point samples_per_pixel */
2379 double f = PBD::atof (prop->value());
2380 reset_zoom (llrintf (f));
2382 reset_zoom (samples_per_pixel);
2385 if ((prop = node.property ("visible-track-count"))) {
2386 set_visible_track_count (PBD::atoi (prop->value()));
2389 if ((prop = node.property ("snap-to"))) {
2390 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2391 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2393 set_snap_to (_snap_type);
2396 if ((prop = node.property ("snap-mode"))) {
2397 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2398 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2399 * snap_mode_selection_done() will only mark an already active item as active
2400 * which does not trigger set_text().
2402 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2404 set_snap_mode (_snap_mode);
2407 if ((prop = node.property ("internal-snap-to"))) {
2408 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2411 if ((prop = node.property ("internal-snap-mode"))) {
2412 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2415 if ((prop = node.property ("pre-internal-snap-to"))) {
2416 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2419 if ((prop = node.property ("pre-internal-snap-mode"))) {
2420 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2423 if ((prop = node.property ("mouse-mode"))) {
2424 MouseMode m = str2mousemode(prop->value());
2425 set_mouse_mode (m, true);
2427 set_mouse_mode (MouseObject, true);
2430 if ((prop = node.property ("left-frame")) != 0) {
2432 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2436 reset_x_origin (pos);
2440 if ((prop = node.property ("y-origin")) != 0) {
2441 reset_y_origin (atof (prop->value ()));
2444 if ((prop = node.property ("join-object-range"))) {
2445 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2446 bool yn = string_is_affirmative (prop->value());
2448 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2449 tact->set_active (!yn);
2450 tact->set_active (yn);
2452 set_mouse_mode(mouse_mode, true);
2455 if ((prop = node.property ("edit-point"))) {
2456 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2458 set_edit_point_preference (_edit_point);
2461 if ((prop = node.property ("show-measures"))) {
2462 bool yn = string_is_affirmative (prop->value());
2463 _show_measures = yn;
2466 if ((prop = node.property ("follow-playhead"))) {
2467 bool yn = string_is_affirmative (prop->value());
2468 set_follow_playhead (yn);
2471 if ((prop = node.property ("stationary-playhead"))) {
2472 bool yn = string_is_affirmative (prop->value());
2473 set_stationary_playhead (yn);
2476 if ((prop = node.property ("region-list-sort-type"))) {
2477 RegionListSortType st;
2478 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2481 if ((prop = node.property ("show-editor-mixer"))) {
2483 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2486 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2487 bool yn = string_is_affirmative (prop->value());
2489 /* do it twice to force the change */
2491 tact->set_active (!yn);
2492 tact->set_active (yn);
2495 if ((prop = node.property ("show-editor-list"))) {
2497 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2500 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2501 bool yn = string_is_affirmative (prop->value());
2503 /* do it twice to force the change */
2505 tact->set_active (!yn);
2506 tact->set_active (yn);
2509 if ((prop = node.property (X_("editor-list-page")))) {
2510 _the_notebook.set_current_page (atoi (prop->value ()));
2513 if ((prop = node.property (X_("show-marker-lines")))) {
2514 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2516 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2517 bool yn = string_is_affirmative (prop->value ());
2519 tact->set_active (!yn);
2520 tact->set_active (yn);
2523 XMLNodeList children = node.children ();
2524 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2525 selection->set_state (**i, Stateful::current_state_version);
2526 _regions->set_state (**i);
2527 _locations->set_state (**i);
2530 if ((prop = node.property ("maximised"))) {
2531 bool yn = string_is_affirmative (prop->value());
2532 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2534 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2535 bool fs = tact && tact->get_active();
2537 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2541 if ((prop = node.property ("nudge-clock-value"))) {
2543 sscanf (prop->value().c_str(), "%" PRId64, &f);
2544 nudge_clock->set (f);
2546 nudge_clock->set_mode (AudioClock::Timecode);
2547 nudge_clock->set (_session->frame_rate() * 5, true);
2552 * Not all properties may have been in XML, but
2553 * those that are linked to a private variable may need changing
2558 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2560 yn = _show_measures;
2561 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2562 /* do it twice to force the change */
2563 tact->set_active (!yn);
2564 tact->set_active (yn);
2567 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2568 yn = _follow_playhead;
2570 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2571 if (tact->get_active() != yn) {
2572 tact->set_active (yn);
2576 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2577 yn = _stationary_playhead;
2579 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2580 if (tact->get_active() != yn) {
2581 tact->set_active (yn);
2586 return LuaInstance::instance()->set_state(node);
2590 Editor::get_state ()
2592 XMLNode* node = new XMLNode (X_("Editor"));
2596 id().print (buf, sizeof (buf));
2597 node->add_property ("id", buf);
2599 node->add_child_nocopy (Tabbable::get_state());
2601 snprintf(buf,sizeof(buf), "%f", edit_pane.get_divider ());
2602 node->add_property("edit-horizontal-pane-pos", string(buf));
2603 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2604 snprintf(buf,sizeof(buf), "%f", editor_summary_pane.get_divider());
2605 node->add_property("edit-vertical-pane-pos", string(buf));
2607 maybe_add_mixer_strip_width (*node);
2609 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2611 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2612 node->add_property ("zoom", buf);
2613 node->add_property ("snap-to", enum_2_string (_snap_type));
2614 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2615 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2616 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2617 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2618 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2619 node->add_property ("edit-point", enum_2_string (_edit_point));
2620 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2621 node->add_property ("visible-track-count", buf);
2623 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2624 node->add_property ("playhead", buf);
2625 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2626 node->add_property ("left-frame", buf);
2627 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2628 node->add_property ("y-origin", buf);
2630 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2631 node->add_property ("maximised", _maximised ? "yes" : "no");
2632 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2633 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2634 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2635 node->add_property ("mouse-mode", enum2str(mouse_mode));
2636 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2638 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2640 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2641 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2644 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2646 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2647 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2650 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2651 node->add_property (X_("editor-list-page"), buf);
2653 if (button_bindings) {
2654 XMLNode* bb = new XMLNode (X_("Buttons"));
2655 button_bindings->save (*bb);
2656 node->add_child_nocopy (*bb);
2659 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2661 node->add_child_nocopy (selection->get_state ());
2662 node->add_child_nocopy (_regions->get_state ());
2664 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2665 node->add_property ("nudge-clock-value", buf);
2667 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2668 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2669 node->add_child_nocopy (_locations->get_state ());
2674 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2675 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2677 * @return pair: TimeAxisView that y is over, layer index.
2679 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2680 * in stacked or expanded region display mode, otherwise 0.
2682 std::pair<TimeAxisView *, double>
2683 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2685 if (!trackview_relative_offset) {
2686 y -= _trackview_group->canvas_origin().y;
2690 return std::make_pair ( (TimeAxisView *) 0, 0);
2693 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2695 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2702 return std::make_pair ( (TimeAxisView *) 0, 0);
2705 /** Snap a position to the grid, if appropriate, taking into account current
2706 * grid settings and also the state of any snap modifier keys that may be pressed.
2707 * @param start Position to snap.
2708 * @param event Event to get current key modifier information from, or 0.
2711 Editor::snap_to_with_modifier (MusicFrame& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2713 if (!_session || !event) {
2717 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2718 if (_snap_mode == SnapOff) {
2719 snap_to_internal (start, direction, for_mark);
2721 start.set (start.frame, 0);
2724 if (_snap_mode != SnapOff) {
2725 snap_to_internal (start, direction, for_mark);
2726 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2727 /* SnapOff, but we pressed the snap_delta modifier */
2728 snap_to_internal (start, direction, for_mark);
2730 start.set (start.frame, 0);
2736 Editor::snap_to (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap)
2738 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2739 start.set (start.frame, 0);
2743 snap_to_internal (start, direction, for_mark, ensure_snap);
2747 Editor::timecode_snap_to_internal (MusicFrame& pos, RoundMode direction, bool /*for_mark*/)
2749 framepos_t start = pos.frame;
2750 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2751 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2753 switch (_snap_type) {
2754 case SnapToTimecodeFrame:
2755 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2756 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2757 /* start is already on a whole timecode frame, do nothing */
2758 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2759 start = (framepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2761 start = (framepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2765 case SnapToTimecodeSeconds:
2766 if (_session->config.get_timecode_offset_negative()) {
2767 start += _session->config.get_timecode_offset ();
2769 start -= _session->config.get_timecode_offset ();
2771 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2772 (start % one_timecode_second == 0)) {
2773 /* start is already on a whole second, do nothing */
2774 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2775 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2777 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2780 if (_session->config.get_timecode_offset_negative()) {
2781 start -= _session->config.get_timecode_offset ();
2783 start += _session->config.get_timecode_offset ();
2787 case SnapToTimecodeMinutes:
2788 if (_session->config.get_timecode_offset_negative()) {
2789 start += _session->config.get_timecode_offset ();
2791 start -= _session->config.get_timecode_offset ();
2793 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2794 (start % one_timecode_minute == 0)) {
2795 /* start is already on a whole minute, do nothing */
2796 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2797 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2799 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2801 if (_session->config.get_timecode_offset_negative()) {
2802 start -= _session->config.get_timecode_offset ();
2804 start += _session->config.get_timecode_offset ();
2808 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2809 abort(); /*NOTREACHED*/
2816 Editor::snap_to_internal (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap)
2818 const framepos_t one_second = _session->frame_rate();
2819 const framepos_t one_minute = _session->frame_rate() * 60;
2820 framepos_t presnap = start.frame;
2824 switch (_snap_type) {
2825 case SnapToTimecodeFrame:
2826 case SnapToTimecodeSeconds:
2827 case SnapToTimecodeMinutes:
2828 return timecode_snap_to_internal (start, direction, for_mark);
2831 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2832 start.frame % (one_second/75) == 0) {
2833 /* start is already on a whole CD frame, do nothing */
2834 } else if (((direction == 0) && (start.frame % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2835 start.frame = (framepos_t) ceil ((double) start.frame / (one_second / 75)) * (one_second / 75);
2837 start.frame = (framepos_t) floor ((double) start.frame / (one_second / 75)) * (one_second / 75);
2840 start.set (start.frame, 0);
2845 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2846 start.frame % one_second == 0) {
2847 /* start is already on a whole second, do nothing */
2848 } else if (((direction == 0) && (start.frame % one_second > one_second / 2)) || (direction > 0)) {
2849 start.frame = (framepos_t) ceil ((double) start.frame / one_second) * one_second;
2851 start.frame = (framepos_t) floor ((double) start.frame / one_second) * one_second;
2854 start.set (start.frame, 0);
2859 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2860 start.frame % one_minute == 0) {
2861 /* start is already on a whole minute, do nothing */
2862 } else if (((direction == 0) && (start.frame % one_minute > one_minute / 2)) || (direction > 0)) {
2863 start.frame = (framepos_t) ceil ((double) start.frame / one_minute) * one_minute;
2865 start.frame = (framepos_t) floor ((double) start.frame / one_minute) * one_minute;
2868 start.set (start.frame, 0);
2873 start = _session->tempo_map().round_to_bar (start.frame, direction);
2877 start = _session->tempo_map().round_to_beat (start.frame, direction);
2880 case SnapToBeatDiv128:
2881 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 128, direction);
2883 case SnapToBeatDiv64:
2884 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 64, direction);
2886 case SnapToBeatDiv32:
2887 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 32, direction);
2889 case SnapToBeatDiv28:
2890 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 28, direction);
2892 case SnapToBeatDiv24:
2893 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 24, direction);
2895 case SnapToBeatDiv20:
2896 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 20, direction);
2898 case SnapToBeatDiv16:
2899 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 16, direction);
2901 case SnapToBeatDiv14:
2902 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 14, direction);
2904 case SnapToBeatDiv12:
2905 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 12, direction);
2907 case SnapToBeatDiv10:
2908 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 10, direction);
2910 case SnapToBeatDiv8:
2911 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 8, direction);
2913 case SnapToBeatDiv7:
2914 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 7, direction);
2916 case SnapToBeatDiv6:
2917 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 6, direction);
2919 case SnapToBeatDiv5:
2920 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 5, direction);
2922 case SnapToBeatDiv4:
2923 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 4, direction);
2925 case SnapToBeatDiv3:
2926 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 3, direction);
2928 case SnapToBeatDiv2:
2929 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 2, direction);
2937 _session->locations()->marks_either_side (start.frame, before, after);
2939 if (before == max_framepos && after == max_framepos) {
2940 /* No marks to snap to, so just don't snap */
2942 } else if (before == max_framepos) {
2943 start.frame = after;
2944 } else if (after == max_framepos) {
2945 start.frame = before;
2946 } else if (before != max_framepos && after != max_framepos) {
2947 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2948 start.frame = after;
2949 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2950 start.frame = before;
2951 else if (direction == 0 ) {
2952 if ((start.frame - before) < (after - start.frame)) {
2953 start.frame = before;
2955 start.frame = after;
2960 start.set (start.frame, 0);
2964 case SnapToRegionStart:
2965 case SnapToRegionEnd:
2966 case SnapToRegionSync:
2967 case SnapToRegionBoundary:
2968 if (!region_boundary_cache.empty()) {
2970 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2971 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2973 if (direction > 0) {
2974 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame);
2976 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame);
2979 if (next != region_boundary_cache.begin ()) {
2984 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2985 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2987 if (start.frame > (p + n) / 2) {
2994 start.set (start.frame, 0);
2999 switch (_snap_mode) {
3009 if (presnap > start.frame) {
3010 if (presnap > (start.frame + pixel_to_sample(snap_threshold))) {
3011 start.set (presnap, 0);
3014 } else if (presnap < start.frame) {
3015 if (presnap < (start.frame - pixel_to_sample(snap_threshold))) {
3016 start.set (presnap, 0);
3021 /* handled at entry */
3028 Editor::setup_toolbar ()
3030 HBox* mode_box = manage(new HBox);
3031 mode_box->set_border_width (2);
3032 mode_box->set_spacing(2);
3034 HBox* mouse_mode_box = manage (new HBox);
3035 HBox* mouse_mode_hbox = manage (new HBox);
3036 VBox* mouse_mode_vbox = manage (new VBox);
3037 Alignment* mouse_mode_align = manage (new Alignment);
3039 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3040 mouse_mode_size_group->add_widget (smart_mode_button);
3041 mouse_mode_size_group->add_widget (mouse_move_button);
3042 mouse_mode_size_group->add_widget (mouse_cut_button);
3043 mouse_mode_size_group->add_widget (mouse_select_button);
3044 mouse_mode_size_group->add_widget (mouse_timefx_button);
3045 mouse_mode_size_group->add_widget (mouse_audition_button);
3046 mouse_mode_size_group->add_widget (mouse_draw_button);
3047 mouse_mode_size_group->add_widget (mouse_content_button);
3049 if (!Profile->get_mixbus()) {
3050 mouse_mode_size_group->add_widget (zoom_in_button);
3051 mouse_mode_size_group->add_widget (zoom_out_button);
3052 mouse_mode_size_group->add_widget (zoom_out_full_button);
3053 mouse_mode_size_group->add_widget (zoom_focus_selector);
3054 mouse_mode_size_group->add_widget (tav_shrink_button);
3055 mouse_mode_size_group->add_widget (tav_expand_button);
3057 mouse_mode_size_group->add_widget (zoom_preset_selector);
3058 mouse_mode_size_group->add_widget (visible_tracks_selector);
3061 mouse_mode_size_group->add_widget (snap_type_selector);
3062 mouse_mode_size_group->add_widget (snap_mode_selector);
3064 mouse_mode_size_group->add_widget (edit_point_selector);
3065 mouse_mode_size_group->add_widget (edit_mode_selector);
3067 mouse_mode_size_group->add_widget (*nudge_clock);
3068 mouse_mode_size_group->add_widget (nudge_forward_button);
3069 mouse_mode_size_group->add_widget (nudge_backward_button);
3071 mouse_mode_hbox->set_spacing (2);
3073 if (!ARDOUR::Profile->get_trx()) {
3074 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3077 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3078 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3080 if (!ARDOUR::Profile->get_mixbus()) {
3081 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3084 if (!ARDOUR::Profile->get_trx()) {
3085 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3086 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3087 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3088 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3091 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3093 mouse_mode_align->add (*mouse_mode_vbox);
3094 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3096 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3098 edit_mode_selector.set_name ("mouse mode button");
3100 if (!ARDOUR::Profile->get_trx()) {
3101 mode_box->pack_start (edit_mode_selector, false, false);
3104 mode_box->pack_start (*mouse_mode_box, false, false);
3108 _zoom_box.set_spacing (2);
3109 _zoom_box.set_border_width (2);
3113 zoom_preset_selector.set_name ("zoom button");
3114 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
3116 zoom_in_button.set_name ("zoom button");
3117 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3118 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3119 zoom_in_button.set_related_action (act);
3121 zoom_out_button.set_name ("zoom button");
3122 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3123 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3124 zoom_out_button.set_related_action (act);
3126 zoom_out_full_button.set_name ("zoom button");
3127 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3128 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3129 zoom_out_full_button.set_related_action (act);
3131 zoom_focus_selector.set_name ("zoom button");
3133 if (ARDOUR::Profile->get_mixbus()) {
3134 _zoom_box.pack_start (zoom_preset_selector, false, false);
3135 } else if (ARDOUR::Profile->get_trx()) {
3136 mode_box->pack_start (zoom_out_button, false, false);
3137 mode_box->pack_start (zoom_in_button, false, false);
3139 _zoom_box.pack_start (zoom_out_button, false, false);
3140 _zoom_box.pack_start (zoom_in_button, false, false);
3141 _zoom_box.pack_start (zoom_out_full_button, false, false);
3142 _zoom_box.pack_start (zoom_focus_selector, false, false);
3145 /* Track zoom buttons */
3146 _track_box.set_spacing (2);
3147 _track_box.set_border_width (2);
3149 visible_tracks_selector.set_name ("zoom button");
3150 if (Profile->get_mixbus()) {
3151 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3153 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3156 tav_expand_button.set_name ("zoom button");
3157 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3158 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3159 tav_expand_button.set_related_action (act);
3161 tav_shrink_button.set_name ("zoom button");
3162 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3163 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3164 tav_shrink_button.set_related_action (act);
3166 if (ARDOUR::Profile->get_mixbus()) {
3167 _track_box.pack_start (visible_tracks_selector);
3168 } else if (ARDOUR::Profile->get_trx()) {
3169 _track_box.pack_start (tav_shrink_button);
3170 _track_box.pack_start (tav_expand_button);
3172 _track_box.pack_start (visible_tracks_selector);
3173 _track_box.pack_start (tav_shrink_button);
3174 _track_box.pack_start (tav_expand_button);
3177 snap_box.set_spacing (2);
3178 snap_box.set_border_width (2);
3180 snap_type_selector.set_name ("mouse mode button");
3182 snap_mode_selector.set_name ("mouse mode button");
3184 edit_point_selector.set_name ("mouse mode button");
3186 snap_box.pack_start (snap_mode_selector, false, false);
3187 snap_box.pack_start (snap_type_selector, false, false);
3190 HBox *ep_box = manage (new HBox);
3191 ep_box->set_spacing (2);
3192 ep_box->set_border_width (2);
3194 ep_box->pack_start (edit_point_selector, false, false);
3198 HBox *nudge_box = manage (new HBox);
3199 nudge_box->set_spacing (2);
3200 nudge_box->set_border_width (2);
3202 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3203 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3205 nudge_box->pack_start (nudge_backward_button, false, false);
3206 nudge_box->pack_start (nudge_forward_button, false, false);
3207 nudge_box->pack_start (*nudge_clock, false, false);
3210 /* Pack everything in... */
3212 toolbar_hbox.set_spacing (2);
3213 toolbar_hbox.set_border_width (2);
3215 toolbar_hbox.pack_start (*mode_box, false, false);
3217 if (!ARDOUR::Profile->get_trx()) {
3219 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3221 toolbar_hbox.pack_start (_zoom_box, false, false);
3223 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3225 toolbar_hbox.pack_start (_track_box, false, false);
3227 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3229 toolbar_hbox.pack_start (snap_box, false, false);
3231 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3233 toolbar_hbox.pack_start (*ep_box, false, false);
3235 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3237 toolbar_hbox.pack_start (*nudge_box, false, false);
3240 toolbar_hbox.show_all ();
3244 Editor::build_edit_point_menu ()
3246 using namespace Menu_Helpers;
3248 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3249 if(!Profile->get_mixbus())
3250 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3251 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3253 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3257 Editor::build_edit_mode_menu ()
3259 using namespace Menu_Helpers;
3261 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3262 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3263 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3264 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3266 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3270 Editor::build_snap_mode_menu ()
3272 using namespace Menu_Helpers;
3274 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3275 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3276 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3278 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3282 Editor::build_snap_type_menu ()
3284 using namespace Menu_Helpers;
3286 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3287 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3288 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3289 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3290 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3291 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3292 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3293 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3294 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3295 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3296 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3297 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3298 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3299 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3300 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3301 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3302 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3303 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3304 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3305 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3306 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3307 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3308 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3309 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3310 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3311 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3312 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3313 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3314 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3315 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3317 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3322 Editor::setup_tooltips ()
3324 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3325 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3326 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3327 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3328 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3329 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3330 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3331 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3332 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3333 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3334 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3335 set_tooltip (zoom_in_button, _("Zoom In"));
3336 set_tooltip (zoom_out_button, _("Zoom Out"));
3337 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3338 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3339 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3340 set_tooltip (tav_expand_button, _("Expand Tracks"));
3341 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3342 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3343 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3344 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3345 set_tooltip (edit_point_selector, _("Edit Point"));
3346 set_tooltip (edit_mode_selector, _("Edit Mode"));
3347 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3351 Editor::convert_drop_to_paths (
3352 vector<string>& paths,
3353 const RefPtr<Gdk::DragContext>& /*context*/,
3356 const SelectionData& data,
3360 if (_session == 0) {
3364 vector<string> uris = data.get_uris();
3368 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3369 are actually URI lists. So do it by hand.
3372 if (data.get_target() != "text/plain") {
3376 /* Parse the "uri-list" format that Nautilus provides,
3377 where each pathname is delimited by \r\n.
3379 THERE MAY BE NO NULL TERMINATING CHAR!!!
3382 string txt = data.get_text();
3386 p = (char *) malloc (txt.length() + 1);
3387 txt.copy (p, txt.length(), 0);
3388 p[txt.length()] = '\0';
3394 while (g_ascii_isspace (*p))
3398 while (*q && (*q != '\n') && (*q != '\r')) {
3405 while (q > p && g_ascii_isspace (*q))
3410 uris.push_back (string (p, q - p + 1));
3414 p = strchr (p, '\n');
3426 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3427 if ((*i).substr (0,7) == "file://") {
3428 paths.push_back (Glib::filename_from_uri (*i));
3436 Editor::new_tempo_section ()
3441 Editor::map_transport_state ()
3443 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3445 if (_session && _session->transport_stopped()) {
3446 have_pending_keyboard_selection = false;
3449 update_loop_range_view ();
3453 Editor::transport_looped ()
3455 /* reset Playhead position interpolation.
3456 * see Editor::super_rapid_screen_update
3458 _last_update_time = 0;
3464 Editor::begin_selection_op_history ()
3466 selection_op_cmd_depth = 0;
3467 selection_op_history_it = 0;
3469 while(!selection_op_history.empty()) {
3470 delete selection_op_history.front();
3471 selection_op_history.pop_front();
3474 selection_undo_action->set_sensitive (false);
3475 selection_redo_action->set_sensitive (false);
3476 selection_op_history.push_front (&_selection_memento->get_state ());
3480 Editor::begin_reversible_selection_op (string name)
3483 //cerr << name << endl;
3484 /* begin/commit pairs can be nested */
3485 selection_op_cmd_depth++;
3490 Editor::commit_reversible_selection_op ()
3493 if (selection_op_cmd_depth == 1) {
3495 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3497 The user has undone some selection ops and then made a new one,
3498 making anything earlier in the list invalid.
3501 list<XMLNode *>::iterator it = selection_op_history.begin();
3502 list<XMLNode *>::iterator e_it = it;
3503 advance (e_it, selection_op_history_it);
3505 for ( ; it != e_it; ++it) {
3508 selection_op_history.erase (selection_op_history.begin(), e_it);
3511 selection_op_history.push_front (&_selection_memento->get_state ());
3512 selection_op_history_it = 0;
3514 selection_undo_action->set_sensitive (true);
3515 selection_redo_action->set_sensitive (false);
3518 if (selection_op_cmd_depth > 0) {
3519 selection_op_cmd_depth--;
3525 Editor::undo_selection_op ()
3528 selection_op_history_it++;
3530 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3531 if (n == selection_op_history_it) {
3532 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3533 selection_redo_action->set_sensitive (true);
3537 /* is there an earlier entry? */
3538 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3539 selection_undo_action->set_sensitive (false);
3545 Editor::redo_selection_op ()
3548 if (selection_op_history_it > 0) {
3549 selection_op_history_it--;
3552 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3553 if (n == selection_op_history_it) {
3554 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3555 selection_undo_action->set_sensitive (true);
3560 if (selection_op_history_it == 0) {
3561 selection_redo_action->set_sensitive (false);
3567 Editor::begin_reversible_command (string name)
3570 before.push_back (&_selection_memento->get_state ());
3571 _session->begin_reversible_command (name);
3576 Editor::begin_reversible_command (GQuark q)
3579 before.push_back (&_selection_memento->get_state ());
3580 _session->begin_reversible_command (q);
3585 Editor::abort_reversible_command ()
3588 while(!before.empty()) {
3589 delete before.front();
3592 _session->abort_reversible_command ();
3597 Editor::commit_reversible_command ()
3600 if (before.size() == 1) {
3601 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3602 redo_action->set_sensitive(false);
3603 undo_action->set_sensitive(true);
3604 begin_selection_op_history ();
3607 if (before.empty()) {
3608 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3613 _session->commit_reversible_command ();
3618 Editor::history_changed ()
3622 if (undo_action && _session) {
3623 if (_session->undo_depth() == 0) {
3624 label = S_("Command|Undo");
3626 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3628 undo_action->property_label() = label;
3631 if (redo_action && _session) {
3632 if (_session->redo_depth() == 0) {
3634 redo_action->set_sensitive (false);
3636 label = string_compose(_("Redo (%1)"), _session->next_redo());
3637 redo_action->set_sensitive (true);
3639 redo_action->property_label() = label;
3644 Editor::duplicate_range (bool with_dialog)
3648 RegionSelection rs = get_regions_from_selection_and_entered ();
3650 if ( selection->time.length() == 0 && rs.empty()) {
3656 ArdourDialog win (_("Duplicate"));
3657 Label label (_("Number of duplications:"));
3658 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3659 SpinButton spinner (adjustment, 0.0, 1);
3662 win.get_vbox()->set_spacing (12);
3663 win.get_vbox()->pack_start (hbox);
3664 hbox.set_border_width (6);
3665 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3667 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3668 place, visually. so do this by hand.
3671 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3672 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3673 spinner.grab_focus();
3679 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3680 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3681 win.set_default_response (RESPONSE_ACCEPT);
3683 spinner.grab_focus ();
3685 switch (win.run ()) {
3686 case RESPONSE_ACCEPT:
3692 times = adjustment.get_value();
3695 if ((current_mouse_mode() == Editing::MouseRange)) {
3696 if (selection->time.length()) {
3697 duplicate_selection (times);
3699 } else if (get_smart_mode()) {
3700 if (selection->time.length()) {
3701 duplicate_selection (times);
3703 duplicate_some_regions (rs, times);
3705 duplicate_some_regions (rs, times);
3710 Editor::set_edit_mode (EditMode m)
3712 Config->set_edit_mode (m);
3716 Editor::cycle_edit_mode ()
3718 switch (Config->get_edit_mode()) {
3720 Config->set_edit_mode (Ripple);
3724 Config->set_edit_mode (Lock);
3727 Config->set_edit_mode (Slide);
3733 Editor::edit_mode_selection_done ( EditMode m )
3735 Config->set_edit_mode ( m );
3739 Editor::snap_type_selection_done (SnapType snaptype)
3741 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3743 ract->set_active ();
3748 Editor::snap_mode_selection_done (SnapMode mode)
3750 RefPtr<RadioAction> ract = snap_mode_action (mode);
3753 ract->set_active (true);
3758 Editor::cycle_edit_point (bool with_marker)
3760 if(Profile->get_mixbus())
3761 with_marker = false;
3763 switch (_edit_point) {
3765 set_edit_point_preference (EditAtPlayhead);
3767 case EditAtPlayhead:
3769 set_edit_point_preference (EditAtSelectedMarker);
3771 set_edit_point_preference (EditAtMouse);
3774 case EditAtSelectedMarker:
3775 set_edit_point_preference (EditAtMouse);
3781 Editor::edit_point_selection_done (EditPoint ep)
3783 set_edit_point_preference ( ep );
3787 Editor::build_zoom_focus_menu ()
3789 using namespace Menu_Helpers;
3791 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3792 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3793 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3794 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3795 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3796 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3798 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3802 Editor::zoom_focus_selection_done ( ZoomFocus f )
3804 RefPtr<RadioAction> ract = zoom_focus_action (f);
3806 ract->set_active ();
3811 Editor::build_track_count_menu ()
3813 using namespace Menu_Helpers;
3815 if (!Profile->get_mixbus()) {
3816 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3817 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3818 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3819 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3820 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3821 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3822 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3823 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3824 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3825 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3826 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3827 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3828 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3830 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3831 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3832 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3833 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3834 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3835 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3836 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3837 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3838 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3839 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3841 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3842 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3843 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3844 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3845 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3846 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3847 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3848 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3849 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3850 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3851 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3856 Editor::set_zoom_preset (int64_t ms)
3859 temporal_zoom_session();
3863 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3864 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3868 Editor::set_visible_track_count (int32_t n)
3870 _visible_track_count = n;
3872 /* if the canvas hasn't really been allocated any size yet, just
3873 record the desired number of visible tracks and return. when canvas
3874 allocation happens, we will get called again and then we can do the
3878 if (_visible_canvas_height <= 1) {
3884 DisplaySuspender ds;
3886 if (_visible_track_count > 0) {
3887 h = trackviews_height() / _visible_track_count;
3888 std::ostringstream s;
3889 s << _visible_track_count;
3891 } else if (_visible_track_count == 0) {
3893 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3894 if ((*i)->marked_for_display()) {
3898 h = trackviews_height() / n;
3901 /* negative value means that the visible track count has
3902 been overridden by explicit track height changes.
3904 visible_tracks_selector.set_text (X_("*"));
3908 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3909 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3912 if (str != visible_tracks_selector.get_text()) {
3913 visible_tracks_selector.set_text (str);
3918 Editor::override_visible_track_count ()
3920 _visible_track_count = -1;
3921 visible_tracks_selector.set_text ( _("*") );
3925 Editor::edit_controls_button_release (GdkEventButton* ev)
3927 if (Keyboard::is_context_menu_event (ev)) {
3928 ARDOUR_UI::instance()->add_route ();
3929 } else if (ev->button == 1) {
3930 selection->clear_tracks ();
3937 Editor::mouse_select_button_release (GdkEventButton* ev)
3939 /* this handles just right-clicks */
3941 if (ev->button != 3) {
3949 Editor::set_zoom_focus (ZoomFocus f)
3951 string str = zoom_focus_strings[(int)f];
3953 if (str != zoom_focus_selector.get_text()) {
3954 zoom_focus_selector.set_text (str);
3957 if (zoom_focus != f) {
3964 Editor::cycle_zoom_focus ()
3966 switch (zoom_focus) {
3968 set_zoom_focus (ZoomFocusRight);
3970 case ZoomFocusRight:
3971 set_zoom_focus (ZoomFocusCenter);
3973 case ZoomFocusCenter:
3974 set_zoom_focus (ZoomFocusPlayhead);
3976 case ZoomFocusPlayhead:
3977 set_zoom_focus (ZoomFocusMouse);
3979 case ZoomFocusMouse:
3980 set_zoom_focus (ZoomFocusEdit);
3983 set_zoom_focus (ZoomFocusLeft);
3989 Editor::set_show_measures (bool yn)
3991 if (_show_measures != yn) {
3994 if ((_show_measures = yn) == true) {
3996 tempo_lines->show();
3999 std::vector<TempoMap::BBTPoint> grid;
4000 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
4001 draw_measures (grid);
4009 Editor::toggle_follow_playhead ()
4011 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
4013 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4014 set_follow_playhead (tact->get_active());
4018 /** @param yn true to follow playhead, otherwise false.
4019 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4022 Editor::set_follow_playhead (bool yn, bool catch_up)
4024 if (_follow_playhead != yn) {
4025 if ((_follow_playhead = yn) == true && catch_up) {
4027 reset_x_origin_to_follow_playhead ();
4034 Editor::toggle_stationary_playhead ()
4036 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4038 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4039 set_stationary_playhead (tact->get_active());
4044 Editor::set_stationary_playhead (bool yn)
4046 if (_stationary_playhead != yn) {
4047 if ((_stationary_playhead = yn) == true) {
4049 // FIXME need a 3.0 equivalent of this 2.X call
4050 // update_current_screen ();
4057 Editor::playlist_selector () const
4059 return *_playlist_selector;
4063 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4065 if (paste_count == 0) {
4066 /* don't bother calculating an offset that will be zero anyway */
4070 /* calculate basic unsnapped multi-paste offset */
4071 framecnt_t offset = paste_count * duration;
4073 /* snap offset so pos + offset is aligned to the grid */
4074 MusicFrame offset_pos (pos + offset, 0);
4075 snap_to(offset_pos, RoundUpMaybe);
4076 offset = offset_pos.frame - pos;
4082 Editor::get_grid_beat_divisions(framepos_t position)
4084 switch (_snap_type) {
4085 case SnapToBeatDiv128: return 128;
4086 case SnapToBeatDiv64: return 64;
4087 case SnapToBeatDiv32: return 32;
4088 case SnapToBeatDiv28: return 28;
4089 case SnapToBeatDiv24: return 24;
4090 case SnapToBeatDiv20: return 20;
4091 case SnapToBeatDiv16: return 16;
4092 case SnapToBeatDiv14: return 14;
4093 case SnapToBeatDiv12: return 12;
4094 case SnapToBeatDiv10: return 10;
4095 case SnapToBeatDiv8: return 8;
4096 case SnapToBeatDiv7: return 7;
4097 case SnapToBeatDiv6: return 6;
4098 case SnapToBeatDiv5: return 5;
4099 case SnapToBeatDiv4: return 4;
4100 case SnapToBeatDiv3: return 3;
4101 case SnapToBeatDiv2: return 2;
4107 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4108 if the grid is non-musical, returns 0.
4109 if the grid is snapped to bars, returns -1.
4110 @param event_state the current keyboard modifier mask.
4113 Editor::get_grid_music_divisions (uint32_t event_state)
4115 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4119 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4123 switch (_snap_type) {
4124 case SnapToBeatDiv128: return 128;
4125 case SnapToBeatDiv64: return 64;
4126 case SnapToBeatDiv32: return 32;
4127 case SnapToBeatDiv28: return 28;
4128 case SnapToBeatDiv24: return 24;
4129 case SnapToBeatDiv20: return 20;
4130 case SnapToBeatDiv16: return 16;
4131 case SnapToBeatDiv14: return 14;
4132 case SnapToBeatDiv12: return 12;
4133 case SnapToBeatDiv10: return 10;
4134 case SnapToBeatDiv8: return 8;
4135 case SnapToBeatDiv7: return 7;
4136 case SnapToBeatDiv6: return 6;
4137 case SnapToBeatDiv5: return 5;
4138 case SnapToBeatDiv4: return 4;
4139 case SnapToBeatDiv3: return 3;
4140 case SnapToBeatDiv2: return 2;
4141 case SnapToBeat: return 1;
4142 case SnapToBar : return -1;
4149 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4153 const unsigned divisions = get_grid_beat_divisions(position);
4155 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4158 switch (_snap_type) {
4160 return Evoral::Beats(4.0 / _session->tempo_map().meter_at_frame (position).note_divisor());
4163 const Meter& m = _session->tempo_map().meter_at_frame (position);
4164 return Evoral::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4172 return Evoral::Beats();
4176 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4180 ret = nudge_clock->current_duration (pos);
4181 next = ret + 1; /* XXXX fix me */
4187 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4189 ArdourDialog dialog (_("Playlist Deletion"));
4190 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4191 "If it is kept, its audio files will not be cleaned.\n"
4192 "If it is deleted, audio files used by it alone will be cleaned."),
4195 dialog.set_position (WIN_POS_CENTER);
4196 dialog.get_vbox()->pack_start (label);
4200 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4201 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4202 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4203 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4204 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4206 // by default gtk uses the left most button
4207 keep->grab_focus ();
4209 switch (dialog.run ()) {
4211 /* keep this and all remaining ones */
4216 /* delete this and all others */
4220 case RESPONSE_ACCEPT:
4221 /* delete the playlist */
4225 case RESPONSE_REJECT:
4226 /* keep the playlist */
4238 Editor::audio_region_selection_covers (framepos_t where)
4240 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4241 if ((*a)->region()->covers (where)) {
4250 Editor::prepare_for_cleanup ()
4252 cut_buffer->clear_regions ();
4253 cut_buffer->clear_playlists ();
4255 selection->clear_regions ();
4256 selection->clear_playlists ();
4258 _regions->suspend_redisplay ();
4262 Editor::finish_cleanup ()
4264 _regions->resume_redisplay ();
4268 Editor::transport_loop_location()
4271 return _session->locations()->auto_loop_location();
4278 Editor::transport_punch_location()
4281 return _session->locations()->auto_punch_location();
4288 Editor::control_layout_scroll (GdkEventScroll* ev)
4290 /* Just forward to the normal canvas scroll method. The coordinate
4291 systems are different but since the canvas is always larger than the
4292 track headers, and aligned with the trackview area, this will work.
4294 In the not too distant future this layout is going away anyway and
4295 headers will be on the canvas.
4297 return canvas_scroll_event (ev, false);
4301 Editor::session_state_saved (string)
4304 _snapshots->redisplay ();
4308 Editor::maximise_editing_space ()
4314 Gtk::Window* toplevel = current_toplevel();
4317 toplevel->fullscreen ();
4323 Editor::restore_editing_space ()
4329 Gtk::Window* toplevel = current_toplevel();
4332 toplevel->unfullscreen();
4338 * Make new playlists for a given track and also any others that belong
4339 * to the same active route group with the `select' property.
4344 Editor::new_playlists (TimeAxisView* v)
4346 begin_reversible_command (_("new playlists"));
4347 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4348 _session->playlists->get (playlists);
4349 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4350 commit_reversible_command ();
4354 * Use a copy of the current playlist for a given track and also any others that belong
4355 * to the same active route group with the `select' property.
4360 Editor::copy_playlists (TimeAxisView* v)
4362 begin_reversible_command (_("copy playlists"));
4363 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4364 _session->playlists->get (playlists);
4365 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4366 commit_reversible_command ();
4369 /** Clear the current playlist for a given track and also any others that belong
4370 * to the same active route group with the `select' property.
4375 Editor::clear_playlists (TimeAxisView* v)
4377 begin_reversible_command (_("clear playlists"));
4378 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4379 _session->playlists->get (playlists);
4380 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4381 commit_reversible_command ();
4385 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4387 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4391 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4393 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4397 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4399 atv.clear_playlist ();
4403 Editor::get_y_origin () const
4405 return vertical_adjustment.get_value ();
4408 /** Queue up a change to the viewport x origin.
4409 * @param frame New x origin.
4412 Editor::reset_x_origin (framepos_t frame)
4414 pending_visual_change.add (VisualChange::TimeOrigin);
4415 pending_visual_change.time_origin = frame;
4416 ensure_visual_change_idle_handler ();
4420 Editor::reset_y_origin (double y)
4422 pending_visual_change.add (VisualChange::YOrigin);
4423 pending_visual_change.y_origin = y;
4424 ensure_visual_change_idle_handler ();
4428 Editor::reset_zoom (framecnt_t spp)
4430 if (spp == samples_per_pixel) {
4434 pending_visual_change.add (VisualChange::ZoomLevel);
4435 pending_visual_change.samples_per_pixel = spp;
4436 ensure_visual_change_idle_handler ();
4440 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4442 reset_x_origin (frame);
4445 if (!no_save_visual) {
4446 undo_visual_stack.push_back (current_visual_state(false));
4450 Editor::VisualState::VisualState (bool with_tracks)
4451 : gui_state (with_tracks ? new GUIObjectState : 0)
4455 Editor::VisualState::~VisualState ()
4460 Editor::VisualState*
4461 Editor::current_visual_state (bool with_tracks)
4463 VisualState* vs = new VisualState (with_tracks);
4464 vs->y_position = vertical_adjustment.get_value();
4465 vs->samples_per_pixel = samples_per_pixel;
4466 vs->leftmost_frame = leftmost_frame;
4467 vs->zoom_focus = zoom_focus;
4470 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4477 Editor::undo_visual_state ()
4479 if (undo_visual_stack.empty()) {
4483 VisualState* vs = undo_visual_stack.back();
4484 undo_visual_stack.pop_back();
4487 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4490 use_visual_state (*vs);
4495 Editor::redo_visual_state ()
4497 if (redo_visual_stack.empty()) {
4501 VisualState* vs = redo_visual_stack.back();
4502 redo_visual_stack.pop_back();
4504 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4505 // why do we check here?
4506 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4509 use_visual_state (*vs);
4514 Editor::swap_visual_state ()
4516 if (undo_visual_stack.empty()) {
4517 redo_visual_state ();
4519 undo_visual_state ();
4524 Editor::use_visual_state (VisualState& vs)
4526 PBD::Unwinder<bool> nsv (no_save_visual, true);
4527 DisplaySuspender ds;
4529 vertical_adjustment.set_value (vs.y_position);
4531 set_zoom_focus (vs.zoom_focus);
4532 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4535 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4537 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4538 (*i)->clear_property_cache();
4539 (*i)->reset_visual_state ();
4543 _routes->update_visibility ();
4546 /** This is the core function that controls the zoom level of the canvas. It is called
4547 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4548 * @param spp new number of samples per pixel
4551 Editor::set_samples_per_pixel (framecnt_t spp)
4557 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4558 const framecnt_t lots_of_pixels = 4000;
4560 /* if the zoom level is greater than what you'd get trying to display 3
4561 * days of audio on a really big screen, then it's too big.
4564 if (spp * lots_of_pixels > three_days) {
4568 samples_per_pixel = spp;
4571 tempo_lines->tempo_map_changed();
4574 bool const showing_time_selection = selection->time.length() > 0;
4576 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4577 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4578 (*i)->reshow_selection (selection->time);
4582 ZoomChanged (); /* EMIT_SIGNAL */
4584 ArdourCanvas::GtkCanvasViewport* c;
4586 c = get_track_canvas();
4588 c->canvas()->zoomed ();
4591 if (playhead_cursor) {
4592 playhead_cursor->set_position (playhead_cursor->current_frame ());
4595 refresh_location_display();
4596 _summary->set_overlays_dirty ();
4598 update_marker_labels ();
4604 Editor::playhead_cursor_sample () const
4606 return playhead_cursor->current_frame();
4610 Editor::queue_visual_videotimeline_update ()
4613 * pending_visual_change.add (VisualChange::VideoTimeline);
4614 * or maybe even more specific: which videotimeline-image
4615 * currently it calls update_video_timeline() to update
4616 * _all outdated_ images on the video-timeline.
4617 * see 'exposeimg()' in video_image_frame.cc
4619 ensure_visual_change_idle_handler ();
4623 Editor::ensure_visual_change_idle_handler ()
4625 if (pending_visual_change.idle_handler_id < 0) {
4626 // see comment in add_to_idle_resize above.
4627 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4628 pending_visual_change.being_handled = false;
4633 Editor::_idle_visual_changer (void* arg)
4635 return static_cast<Editor*>(arg)->idle_visual_changer ();
4639 Editor::idle_visual_changer ()
4641 /* set_horizontal_position() below (and maybe other calls) call
4642 gtk_main_iteration(), so it's possible that a signal will be handled
4643 half-way through this method. If this signal wants an
4644 idle_visual_changer we must schedule another one after this one, so
4645 mark the idle_handler_id as -1 here to allow that. Also make a note
4646 that we are doing the visual change, so that changes in response to
4647 super-rapid-screen-update can be dropped if we are still processing
4651 pending_visual_change.idle_handler_id = -1;
4652 pending_visual_change.being_handled = true;
4654 VisualChange vc = pending_visual_change;
4656 pending_visual_change.pending = (VisualChange::Type) 0;
4658 visual_changer (vc);
4660 pending_visual_change.being_handled = false;
4662 return 0; /* this is always a one-shot call */
4666 Editor::visual_changer (const VisualChange& vc)
4668 double const last_time_origin = horizontal_position ();
4670 if (vc.pending & VisualChange::ZoomLevel) {
4671 set_samples_per_pixel (vc.samples_per_pixel);
4673 compute_fixed_ruler_scale ();
4675 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4676 update_tempo_based_rulers ();
4678 update_video_timeline();
4681 if (vc.pending & VisualChange::TimeOrigin) {
4682 set_horizontal_position (sample_to_pixel_unrounded (vc.time_origin));
4685 if (vc.pending & VisualChange::YOrigin) {
4686 vertical_adjustment.set_value (vc.y_origin);
4689 if (last_time_origin == horizontal_position ()) {
4690 /* changed signal not emitted */
4691 update_fixed_rulers ();
4692 redisplay_tempo (true);
4695 if (!(vc.pending & VisualChange::ZoomLevel)) {
4696 update_video_timeline();
4699 _summary->set_overlays_dirty ();
4702 struct EditorOrderTimeAxisSorter {
4703 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4704 return a->order () < b->order ();
4709 Editor::sort_track_selection (TrackViewList& sel)
4711 EditorOrderTimeAxisSorter cmp;
4716 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4719 framepos_t where = 0;
4720 EditPoint ep = _edit_point;
4722 if (Profile->get_mixbus()) {
4723 if (ep == EditAtSelectedMarker) {
4724 ep = EditAtPlayhead;
4728 if (from_outside_canvas && (ep == EditAtMouse)) {
4729 ep = EditAtPlayhead;
4730 } else if (from_context_menu && (ep == EditAtMouse)) {
4731 return canvas_event_sample (&context_click_event, 0, 0);
4734 if (entered_marker) {
4735 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4736 return entered_marker->position();
4739 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4740 ep = EditAtSelectedMarker;
4743 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4744 ep = EditAtPlayhead;
4747 MusicFrame snap_mf (0, 0);
4750 case EditAtPlayhead:
4751 if (_dragging_playhead) {
4752 where = *_control_scroll_target;
4754 where = _session->audible_frame();
4756 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4759 case EditAtSelectedMarker:
4760 if (!selection->markers.empty()) {
4762 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4765 where = loc->start();
4769 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4777 if (!mouse_frame (where, ignored)) {
4778 /* XXX not right but what can we do ? */
4781 snap_mf.frame = where;
4783 where = snap_mf.frame;
4784 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4792 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4794 if (!_session) return;
4796 begin_reversible_command (cmd);
4800 if ((tll = transport_loop_location()) == 0) {
4801 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4802 XMLNode &before = _session->locations()->get_state();
4803 _session->locations()->add (loc, true);
4804 _session->set_auto_loop_location (loc);
4805 XMLNode &after = _session->locations()->get_state();
4806 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4808 XMLNode &before = tll->get_state();
4809 tll->set_hidden (false, this);
4810 tll->set (start, end);
4811 XMLNode &after = tll->get_state();
4812 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4815 commit_reversible_command ();
4819 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4821 if (!_session) return;
4823 begin_reversible_command (cmd);
4827 if ((tpl = transport_punch_location()) == 0) {
4828 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4829 XMLNode &before = _session->locations()->get_state();
4830 _session->locations()->add (loc, true);
4831 _session->set_auto_punch_location (loc);
4832 XMLNode &after = _session->locations()->get_state();
4833 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4835 XMLNode &before = tpl->get_state();
4836 tpl->set_hidden (false, this);
4837 tpl->set (start, end);
4838 XMLNode &after = tpl->get_state();
4839 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4842 commit_reversible_command ();
4845 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4846 * @param rs List to which found regions are added.
4847 * @param where Time to look at.
4848 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4851 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4853 const TrackViewList* tracks;
4856 tracks = &track_views;
4861 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4863 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4866 boost::shared_ptr<Track> tr;
4867 boost::shared_ptr<Playlist> pl;
4869 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4871 boost::shared_ptr<RegionList> regions = pl->regions_at (
4872 (framepos_t) floor ( (double) where * tr->speed()));
4874 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4875 RegionView* rv = rtv->view()->find_view (*i);
4886 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4888 const TrackViewList* tracks;
4891 tracks = &track_views;
4896 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4897 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4899 boost::shared_ptr<Track> tr;
4900 boost::shared_ptr<Playlist> pl;
4902 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4904 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4905 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4907 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4909 RegionView* rv = rtv->view()->find_view (*i);
4920 /** Get regions using the following method:
4922 * Make a region list using:
4923 * (a) any selected regions
4924 * (b) the intersection of any selected tracks and the edit point(*)
4925 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4927 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4929 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4933 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4935 RegionSelection regions;
4937 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4938 regions.add (entered_regionview);
4940 regions = selection->regions;
4943 if ( regions.empty() ) {
4944 TrackViewList tracks = selection->tracks;
4946 if (!tracks.empty()) {
4947 /* no region selected or entered, but some selected tracks:
4948 * act on all regions on the selected tracks at the edit point
4950 framepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
4951 get_regions_at(regions, where, tracks);
4958 /** Get regions using the following method:
4960 * Make a region list using:
4961 * (a) any selected regions
4962 * (b) the intersection of any selected tracks and the edit point(*)
4963 * (c) if neither exists, then whatever region is under the mouse
4965 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4967 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4970 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4972 RegionSelection regions;
4974 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4975 regions.add (entered_regionview);
4977 regions = selection->regions;
4980 if ( regions.empty() ) {
4981 TrackViewList tracks = selection->tracks;
4983 if (!tracks.empty()) {
4984 /* no region selected or entered, but some selected tracks:
4985 * act on all regions on the selected tracks at the edit point
4987 get_regions_at(regions, pos, tracks);
4994 /** Start with regions that are selected, or the entered regionview if none are selected.
4995 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4996 * of the regions that we started with.
5000 Editor::get_regions_from_selection_and_entered () const
5002 RegionSelection regions = selection->regions;
5004 if (regions.empty() && entered_regionview) {
5005 regions.add (entered_regionview);
5012 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
5014 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5015 RouteTimeAxisView* rtav;
5017 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5018 boost::shared_ptr<Playlist> pl;
5019 std::vector<boost::shared_ptr<Region> > results;
5020 boost::shared_ptr<Track> tr;
5022 if ((tr = rtav->track()) == 0) {
5027 if ((pl = (tr->playlist())) != 0) {
5028 boost::shared_ptr<Region> r = pl->region_by_id (id);
5030 RegionView* rv = rtav->view()->find_view (r);
5032 regions.push_back (rv);
5041 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5044 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5045 MidiTimeAxisView* mtav;
5047 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5049 mtav->get_per_region_note_selection (selection);
5056 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5058 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5060 RouteTimeAxisView* tatv;
5062 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5064 boost::shared_ptr<Playlist> pl;
5065 vector<boost::shared_ptr<Region> > results;
5067 boost::shared_ptr<Track> tr;
5069 if ((tr = tatv->track()) == 0) {
5074 if ((pl = (tr->playlist())) != 0) {
5075 if (src_comparison) {
5076 pl->get_source_equivalent_regions (region, results);
5078 pl->get_region_list_equivalent_regions (region, results);
5082 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5083 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5084 regions.push_back (marv);
5093 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
5095 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5096 RouteTimeAxisView* tatv;
5097 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5098 if (!tatv->track()) {
5101 RegionView* marv = tatv->view()->find_view (region);
5111 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5113 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5114 RouteTimeAxisView* rtav;
5115 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5116 if (rtav->route() == route) {
5125 Editor::show_rhythm_ferret ()
5127 if (rhythm_ferret == 0) {
5128 rhythm_ferret = new RhythmFerret(*this);
5131 rhythm_ferret->set_session (_session);
5132 rhythm_ferret->show ();
5133 rhythm_ferret->present ();
5137 Editor::first_idle ()
5139 MessageDialog* dialog = 0;
5141 if (track_views.size() > 1) {
5142 Timers::TimerSuspender t;
5143 dialog = new MessageDialog (
5144 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5148 ARDOUR_UI::instance()->flush_pending (60);
5151 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5155 // first idle adds route children (automation tracks), so we need to redisplay here
5156 _routes->redisplay ();
5160 if (_session->undo_depth() == 0) {
5161 undo_action->set_sensitive(false);
5163 redo_action->set_sensitive(false);
5164 begin_selection_op_history ();
5170 Editor::_idle_resize (gpointer arg)
5172 return ((Editor*)arg)->idle_resize ();
5176 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5178 if (resize_idle_id < 0) {
5179 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5180 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5181 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5183 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5184 _pending_resize_amount = 0;
5187 /* make a note of the smallest resulting height, so that we can clamp the
5188 lower limit at TimeAxisView::hSmall */
5190 int32_t min_resulting = INT32_MAX;
5192 _pending_resize_amount += h;
5193 _pending_resize_view = view;
5195 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5197 if (selection->tracks.contains (_pending_resize_view)) {
5198 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5199 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5203 if (min_resulting < 0) {
5208 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5209 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5213 /** Handle pending resizing of tracks */
5215 Editor::idle_resize ()
5217 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5219 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5220 selection->tracks.contains (_pending_resize_view)) {
5222 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5223 if (*i != _pending_resize_view) {
5224 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5229 _pending_resize_amount = 0;
5230 _group_tabs->set_dirty ();
5231 resize_idle_id = -1;
5239 ENSURE_GUI_THREAD (*this, &Editor::located);
5242 playhead_cursor->set_position (_session->audible_frame ());
5243 if (_follow_playhead && !_pending_initial_locate) {
5244 reset_x_origin_to_follow_playhead ();
5248 _pending_locate_request = false;
5249 _pending_initial_locate = false;
5250 _last_update_time = 0;
5254 Editor::region_view_added (RegionView * rv)
5256 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5257 if (rv->region ()->id () == (*pr)) {
5258 selection->add (rv);
5259 selection->regions.pending.erase (pr);
5264 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5266 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5267 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5268 if (rv->region()->id () == (*rnote).first) {
5269 mrv->select_notes ((*rnote).second);
5270 selection->pending_midi_note_selection.erase(rnote);
5276 _summary->set_background_dirty ();
5280 Editor::region_view_removed ()
5282 _summary->set_background_dirty ();
5286 Editor::axis_view_from_stripable (boost::shared_ptr<Stripable> s) const
5288 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5289 if ((*j)->stripable() == s) {
5299 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5303 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5304 TimeAxisView* tv = axis_view_from_stripable (*i);
5314 Editor::suspend_route_redisplay ()
5317 _routes->suspend_redisplay();
5322 Editor::resume_route_redisplay ()
5325 _routes->redisplay(); // queue redisplay
5326 _routes->resume_redisplay();
5331 Editor::add_vcas (VCAList& vlist)
5335 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5336 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5339 add_stripables (sl);
5343 Editor::add_routes (RouteList& rlist)
5347 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5351 add_stripables (sl);
5355 Editor::add_stripables (StripableList& sl)
5357 list<TimeAxisView*> new_views;
5358 boost::shared_ptr<VCA> v;
5359 boost::shared_ptr<Route> r;
5360 TrackViewList new_selection;
5361 bool from_scratch = (track_views.size() == 0);
5363 sl.sort (StripablePresentationInfoSorter());
5365 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5367 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5369 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5371 new_views.push_back (vtv);
5373 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5375 if (r->is_auditioner() || r->is_monitor()) {
5379 RouteTimeAxisView* rtv;
5380 DataType dt = r->input()->default_type();
5382 if (dt == ARDOUR::DataType::AUDIO) {
5383 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5385 } else if (dt == ARDOUR::DataType::MIDI) {
5386 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5389 throw unknown_type();
5392 new_views.push_back (rtv);
5393 track_views.push_back (rtv);
5394 new_selection.push_back (rtv);
5396 rtv->effective_gain_display ();
5398 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5399 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5403 if (new_views.size() > 0) {
5404 _routes->time_axis_views_added (new_views);
5405 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5408 /* note: !new_selection.empty() means that we got some routes rather
5412 if (!from_scratch && !new_selection.empty()) {
5413 selection->set (new_selection);
5414 begin_selection_op_history();
5417 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5418 show_editor_mixer (true);
5421 editor_list_button.set_sensitive (true);
5425 Editor::timeaxisview_deleted (TimeAxisView *tv)
5427 if (tv == entered_track) {
5431 if (_session && _session->deletion_in_progress()) {
5432 /* the situation is under control */
5436 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5438 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5440 _routes->route_removed (tv);
5442 TimeAxisView::Children c = tv->get_child_list ();
5443 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5444 if (entered_track == i->get()) {
5449 /* remove it from the list of track views */
5451 TrackViewList::iterator i;
5453 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5454 i = track_views.erase (i);
5457 /* update whatever the current mixer strip is displaying, if revelant */
5459 boost::shared_ptr<Route> route;
5462 route = rtav->route ();
5465 if (current_mixer_strip && current_mixer_strip->route() == route) {
5467 TimeAxisView* next_tv;
5469 if (track_views.empty()) {
5471 } else if (i == track_views.end()) {
5472 next_tv = track_views.front();
5477 // skip VCAs (cannot be selected, n/a in editor-mixer)
5478 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5479 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5480 next_tv = track_views.front();
5482 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5483 /* just in case: no master, only a VCA remains */
5489 set_selected_mixer_strip (*next_tv);
5491 /* make the editor mixer strip go away setting the
5492 * button to inactive (which also unticks the menu option)
5495 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5501 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5506 if (apply_to_selection) {
5507 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5509 TrackSelection::iterator j = i;
5512 hide_track_in_display (*i, false);
5517 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5519 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5520 // this will hide the mixer strip
5521 set_selected_mixer_strip (*tv);
5524 _routes->hide_track_in_display (*tv);
5529 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5534 _routes->show_track_in_display (*tv);
5535 if (move_into_view) {
5536 ensure_time_axis_view_is_visible (*tv, false);
5541 Editor::sync_track_view_list_and_routes ()
5543 track_views = TrackViewList (_routes->views ());
5545 _summary->set_background_dirty();
5546 _group_tabs->set_dirty ();
5548 return false; // do not call again (until needed)
5552 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5554 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5559 /** Find a RouteTimeAxisView by the ID of its route */
5561 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5563 RouteTimeAxisView* v;
5565 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5566 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5567 if(v->route()->id() == id) {
5577 Editor::fit_route_group (RouteGroup *g)
5579 TrackViewList ts = axis_views_from_routes (g->route_list ());
5584 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5586 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5589 _session->cancel_audition ();
5593 if (_session->is_auditioning()) {
5594 _session->cancel_audition ();
5595 if (r == last_audition_region) {
5600 _session->audition_region (r);
5601 last_audition_region = r;
5606 Editor::hide_a_region (boost::shared_ptr<Region> r)
5608 r->set_hidden (true);
5612 Editor::show_a_region (boost::shared_ptr<Region> r)
5614 r->set_hidden (false);
5618 Editor::audition_region_from_region_list ()
5620 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5624 Editor::hide_region_from_region_list ()
5626 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5630 Editor::show_region_in_region_list ()
5632 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5636 Editor::step_edit_status_change (bool yn)
5639 start_step_editing ();
5641 stop_step_editing ();
5646 Editor::start_step_editing ()
5648 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5652 Editor::stop_step_editing ()
5654 step_edit_connection.disconnect ();
5658 Editor::check_step_edit ()
5660 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5661 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5663 mtv->check_step_edit ();
5667 return true; // do it again, till we stop
5671 Editor::scroll_press (Direction dir)
5673 ++_scroll_callbacks;
5675 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5676 /* delay the first auto-repeat */
5682 scroll_backward (1);
5690 scroll_up_one_track ();
5694 scroll_down_one_track ();
5698 /* do hacky auto-repeat */
5699 if (!_scroll_connection.connected ()) {
5701 _scroll_connection = Glib::signal_timeout().connect (
5702 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5705 _scroll_callbacks = 0;
5712 Editor::scroll_release ()
5714 _scroll_connection.disconnect ();
5717 /** Queue a change for the Editor viewport x origin to follow the playhead */
5719 Editor::reset_x_origin_to_follow_playhead ()
5721 framepos_t const frame = playhead_cursor->current_frame ();
5723 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5725 if (_session->transport_speed() < 0) {
5727 if (frame > (current_page_samples() / 2)) {
5728 center_screen (frame-(current_page_samples()/2));
5730 center_screen (current_page_samples()/2);
5737 if (frame < leftmost_frame) {
5739 if (_session->transport_rolling()) {
5740 /* rolling; end up with the playhead at the right of the page */
5741 l = frame - current_page_samples ();
5743 /* not rolling: end up with the playhead 1/4 of the way along the page */
5744 l = frame - current_page_samples() / 4;
5748 if (_session->transport_rolling()) {
5749 /* rolling: end up with the playhead on the left of the page */
5752 /* not rolling: end up with the playhead 3/4 of the way along the page */
5753 l = frame - 3 * current_page_samples() / 4;
5761 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5767 Editor::super_rapid_screen_update ()
5769 if (!_session || !_session->engine().running()) {
5773 /* METERING / MIXER STRIPS */
5775 /* update track meters, if required */
5776 if (contents().is_mapped() && meters_running) {
5777 RouteTimeAxisView* rtv;
5778 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5779 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5780 rtv->fast_update ();
5785 /* and any current mixer strip */
5786 if (current_mixer_strip) {
5787 current_mixer_strip->fast_update ();
5790 /* PLAYHEAD AND VIEWPORT */
5792 /* There are a few reasons why we might not update the playhead / viewport stuff:
5794 * 1. we don't update things when there's a pending locate request, otherwise
5795 * when the editor requests a locate there is a chance that this method
5796 * will move the playhead before the locate request is processed, causing
5798 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5799 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5801 if (_pending_locate_request || !_session->transport_rolling ()) {
5802 _last_update_time = 0;
5806 if (_dragging_playhead) {
5807 _last_update_time = 0;
5811 bool latent_locate = false;
5812 framepos_t frame = _session->audible_frame (&latent_locate);
5813 const int64_t now = g_get_monotonic_time ();
5816 if (_last_update_time > 0) {
5817 const double ds = (now - _last_update_time) * _session->transport_speed() * _session->nominal_frame_rate () * 1e-6;
5818 framepos_t guess = playhead_cursor->current_frame () + rint (ds);
5819 err = frame - guess;
5821 guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update)
5822 _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2
5825 printf ("eng: %ld gui:%ld (%+6.1f) diff: %6.1f (err: %7.2f)\n",
5827 err, _err_screen_engine);
5832 _err_screen_engine = 0;
5835 if (err > 8192 || latent_locate) {
5836 // in case of x-runs or freewheeling
5837 _last_update_time = 0;
5839 _last_update_time = now;
5842 if (playhead_cursor->current_frame () == frame) {
5846 playhead_cursor->set_position (frame);
5848 if (_session->requested_return_frame() >= 0) {
5849 _last_update_time = 0;
5853 if (!_follow_playhead || pending_visual_change.being_handled) {
5854 /* We only do this if we aren't already
5855 * handling a visual change (ie if
5856 * pending_visual_change.being_handled is
5857 * false) so that these requests don't stack
5858 * up there are too many of them to handle in
5864 if (!_stationary_playhead) {
5865 reset_x_origin_to_follow_playhead ();
5867 framepos_t const frame = playhead_cursor->current_frame ();
5868 double target = ((double)frame - (double)current_page_samples() / 2.0);
5869 if (target <= 0.0) {
5872 // compare to EditorCursor::set_position()
5873 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5874 double const new_pos = sample_to_pixel_unrounded (target);
5875 if (rint (new_pos) != rint (old_pos)) {
5876 reset_x_origin (pixel_to_sample (new_pos));
5883 Editor::session_going_away ()
5885 _have_idled = false;
5887 _session_connections.drop_connections ();
5889 super_rapid_screen_update_connection.disconnect ();
5891 selection->clear ();
5892 cut_buffer->clear ();
5894 clicked_regionview = 0;
5895 clicked_axisview = 0;
5896 clicked_routeview = 0;
5897 entered_regionview = 0;
5899 _last_update_time = 0;
5902 playhead_cursor->hide ();
5904 /* rip everything out of the list displays */
5908 _route_groups->clear ();
5910 /* do this first so that deleting a track doesn't reset cms to null
5911 and thus cause a leak.
5914 if (current_mixer_strip) {
5915 if (current_mixer_strip->get_parent() != 0) {
5916 global_hpacker.remove (*current_mixer_strip);
5918 delete current_mixer_strip;
5919 current_mixer_strip = 0;
5922 /* delete all trackviews */
5924 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5927 track_views.clear ();
5929 nudge_clock->set_session (0);
5931 editor_list_button.set_active(false);
5932 editor_list_button.set_sensitive(false);
5934 /* clear tempo/meter rulers */
5935 remove_metric_marks ();
5937 clear_marker_display ();
5939 stop_step_editing ();
5943 /* get rid of any existing editor mixer strip */
5945 WindowTitle title(Glib::get_application_name());
5946 title += _("Editor");
5948 own_window()->set_title (title.get_string());
5951 SessionHandlePtr::session_going_away ();
5955 Editor::trigger_script (int i)
5957 LuaInstance::instance()-> call_action (i);
5961 Editor::show_editor_list (bool yn)
5964 _editor_list_vbox.show ();
5966 _editor_list_vbox.hide ();
5971 Editor::change_region_layering_order (bool from_context_menu)
5973 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5975 if (!clicked_routeview) {
5976 if (layering_order_editor) {
5977 layering_order_editor->hide ();
5982 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5988 boost::shared_ptr<Playlist> pl = track->playlist();
5994 if (layering_order_editor == 0) {
5995 layering_order_editor = new RegionLayeringOrderEditor (*this);
5998 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5999 layering_order_editor->maybe_present ();
6003 Editor::update_region_layering_order_editor ()
6005 if (layering_order_editor && layering_order_editor->is_visible ()) {
6006 change_region_layering_order (true);
6011 Editor::setup_fade_images ()
6013 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
6014 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
6015 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
6016 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
6017 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
6019 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
6020 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
6021 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
6022 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
6023 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
6027 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
6029 Editor::action_menu_item (std::string const & name)
6031 Glib::RefPtr<Action> a = editor_actions->get_action (name);
6034 return *manage (a->create_menu_item ());
6038 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
6040 EventBox* b = manage (new EventBox);
6041 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
6042 Label* l = manage (new Label (name));
6046 _the_notebook.append_page (widget, *b);
6050 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6052 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6053 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6056 if (ev->type == GDK_2BUTTON_PRESS) {
6058 /* double-click on a notebook tab shrinks or expands the notebook */
6060 if (_notebook_shrunk) {
6061 if (pre_notebook_shrink_pane_width) {
6062 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6064 _notebook_shrunk = false;
6066 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6068 /* this expands the LHS of the edit pane to cover the notebook
6069 PAGE but leaves the tabs visible.
6071 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6072 _notebook_shrunk = true;
6080 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6082 using namespace Menu_Helpers;
6084 MenuList& items = _control_point_context_menu.items ();
6087 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6088 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6089 if (!can_remove_control_point (item)) {
6090 items.back().set_sensitive (false);
6093 _control_point_context_menu.popup (event->button.button, event->button.time);
6097 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6099 using namespace Menu_Helpers;
6101 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6106 /* We need to get the selection here and pass it to the operations, since
6107 popping up the menu will cause a region leave event which clears
6108 entered_regionview. */
6110 MidiRegionView& mrv = note->region_view();
6111 const RegionSelection rs = get_regions_from_selection_and_entered ();
6112 const uint32_t sel_size = mrv.selection_size ();
6114 MenuList& items = _note_context_menu.items();
6118 items.push_back(MenuElem(_("Delete"),
6119 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6122 items.push_back(MenuElem(_("Edit..."),
6123 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6124 if (sel_size != 1) {
6125 items.back().set_sensitive (false);
6128 items.push_back(MenuElem(_("Transpose..."),
6129 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6132 items.push_back(MenuElem(_("Legatize"),
6133 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6135 items.back().set_sensitive (false);
6138 items.push_back(MenuElem(_("Quantize..."),
6139 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6141 items.push_back(MenuElem(_("Remove Overlap"),
6142 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6144 items.back().set_sensitive (false);
6147 items.push_back(MenuElem(_("Transform..."),
6148 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6150 _note_context_menu.popup (event->button.button, event->button.time);
6154 Editor::zoom_vertical_modifier_released()
6156 _stepping_axis_view = 0;
6160 Editor::ui_parameter_changed (string parameter)
6162 if (parameter == "icon-set") {
6163 while (!_cursor_stack.empty()) {
6164 _cursor_stack.pop_back();
6166 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6167 _cursor_stack.push_back(_cursors->grabber);
6168 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6169 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6171 } else if (parameter == "draggable-playhead") {
6172 if (_verbose_cursor) {
6173 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6179 Editor::use_own_window (bool and_fill_it)
6181 bool new_window = !own_window();
6183 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6185 if (win && new_window) {
6186 win->set_name ("EditorWindow");
6188 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6190 // win->signal_realize().connect (*this, &Editor::on_realize);
6191 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6192 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6193 win->set_data ("ardour-bindings", bindings);
6198 DisplaySuspender ds;
6199 contents().show_all ();
6201 /* XXX: this is a bit unfortunate; it would probably
6202 be nicer if we could just call show () above rather
6203 than needing the show_all ()
6206 /* re-hide stuff if necessary */
6207 editor_list_button_toggled ();
6208 parameter_changed ("show-summary");
6209 parameter_changed ("show-group-tabs");
6210 parameter_changed ("show-zoom-tools");
6212 /* now reset all audio_time_axis heights, because widgets might need
6218 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6219 tv = (static_cast<TimeAxisView*>(*i));
6220 tv->reset_height ();
6223 if (current_mixer_strip) {
6224 current_mixer_strip->hide_things ();
6225 current_mixer_strip->parameter_changed ("mixer-element-visibility");