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_frame (0)
347 , cut_buffer_start (0)
348 , cut_buffer_length (0)
349 , button_bindings (0)
353 , current_interthread_info (0)
354 , analysis_window (0)
355 , select_new_marker (false)
357 , scrubbing_direction (0)
358 , scrub_reversals (0)
359 , scrub_reverse_distance (0)
360 , have_pending_keyboard_selection (false)
361 , pending_keyboard_selection_start (0)
362 , _snap_type (SnapToBeat)
363 , _snap_mode (SnapOff)
364 , snap_threshold (5.0)
365 , ignore_gui_changes (false)
366 , _drags (new DragManager (this))
368 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
369 , _dragging_playhead (false)
370 , _dragging_edit_point (false)
371 , _show_measures (true)
372 , _follow_playhead (true)
373 , _stationary_playhead (false)
376 , global_rect_group (0)
377 , time_line_group (0)
378 , tempo_marker_menu (0)
379 , meter_marker_menu (0)
381 , range_marker_menu (0)
382 , transport_marker_menu (0)
383 , new_transport_marker_menu (0)
385 , marker_menu_item (0)
386 , bbt_beat_subdivision (4)
387 , _visible_track_count (-1)
388 , toolbar_selection_clock_table (2,3)
389 , automation_mode_button (_("mode"))
390 , selection (new Selection (this))
391 , cut_buffer (new Selection (this))
392 , _selection_memento (new SelectionMemento())
393 , _all_region_actions_sensitized (false)
394 , _ignore_region_action (false)
395 , _last_region_menu_was_main (false)
396 , _track_selection_change_without_scroll (false)
397 , cd_marker_bar_drag_rect (0)
398 , range_bar_drag_rect (0)
399 , transport_bar_drag_rect (0)
400 , transport_bar_range_rect (0)
401 , transport_bar_preroll_rect (0)
402 , transport_bar_postroll_rect (0)
403 , transport_loop_range_rect (0)
404 , transport_punch_range_rect (0)
405 , transport_punchin_line (0)
406 , transport_punchout_line (0)
407 , transport_preroll_rect (0)
408 , transport_postroll_rect (0)
410 , rubberband_rect (0)
416 , autoscroll_horizontal_allowed (false)
417 , autoscroll_vertical_allowed (false)
419 , autoscroll_widget (0)
420 , show_gain_after_trim (false)
421 , selection_op_cmd_depth (0)
422 , selection_op_history_it (0)
423 , no_save_instant (false)
425 , current_mixer_strip (0)
426 , show_editor_mixer_when_tracks_arrive (false)
427 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
428 , current_stepping_trackview (0)
429 , last_track_height_step_timestamp (0)
431 , entered_regionview (0)
432 , clear_entered_track (false)
433 , _edit_point (EditAtMouse)
434 , meters_running (false)
436 , _have_idled (false)
437 , resize_idle_id (-1)
438 , _pending_resize_amount (0)
439 , _pending_resize_view (0)
440 , _pending_locate_request (false)
441 , _pending_initial_locate (false)
445 , layering_order_editor (0)
446 , _last_cut_copy_source_track (0)
447 , _region_selection_change_updates_region_list (true)
449 , _following_mixer_selection (false)
450 , _control_point_toggled_on_press (false)
451 , _stepping_axis_view (0)
452 , quantize_dialog (0)
453 , _main_menu_disabler (0)
454 , myactions (X_("editor"))
456 /* we are a singleton */
458 PublicEditor::_instance = this;
462 last_event_time.tv_sec = 0;
463 last_event_time.tv_usec = 0;
465 selection_op_history.clear();
468 snap_type_strings = I18N (_snap_type_strings);
469 snap_mode_strings = I18N (_snap_mode_strings);
470 zoom_focus_strings = I18N (_zoom_focus_strings);
471 edit_mode_strings = I18N (_edit_mode_strings);
472 edit_point_strings = I18N (_edit_point_strings);
473 #ifdef USE_RUBBERBAND
474 rb_opt_strings = I18N (_rb_opt_strings);
478 build_edit_mode_menu();
479 build_zoom_focus_menu();
480 build_track_count_menu();
481 build_snap_mode_menu();
482 build_snap_type_menu();
483 build_edit_point_menu();
485 location_marker_color = UIConfiguration::instance().color ("location marker");
486 location_range_color = UIConfiguration::instance().color ("location range");
487 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
488 location_loop_color = UIConfiguration::instance().color ("location loop");
489 location_punch_color = UIConfiguration::instance().color ("location punch");
491 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
493 TimeAxisView::setup_sizes ();
494 ArdourMarker::setup_sizes (timebar_height);
495 TempoCurve::setup_sizes (timebar_height);
497 bbt_label.set_name ("EditorRulerLabel");
498 bbt_label.set_size_request (-1, (int)timebar_height);
499 bbt_label.set_alignment (1.0, 0.5);
500 bbt_label.set_padding (5,0);
502 bbt_label.set_no_show_all();
503 minsec_label.set_name ("EditorRulerLabel");
504 minsec_label.set_size_request (-1, (int)timebar_height);
505 minsec_label.set_alignment (1.0, 0.5);
506 minsec_label.set_padding (5,0);
507 minsec_label.hide ();
508 minsec_label.set_no_show_all();
509 timecode_label.set_name ("EditorRulerLabel");
510 timecode_label.set_size_request (-1, (int)timebar_height);
511 timecode_label.set_alignment (1.0, 0.5);
512 timecode_label.set_padding (5,0);
513 timecode_label.hide ();
514 timecode_label.set_no_show_all();
515 samples_label.set_name ("EditorRulerLabel");
516 samples_label.set_size_request (-1, (int)timebar_height);
517 samples_label.set_alignment (1.0, 0.5);
518 samples_label.set_padding (5,0);
519 samples_label.hide ();
520 samples_label.set_no_show_all();
522 tempo_label.set_name ("EditorRulerLabel");
523 tempo_label.set_size_request (-1, (int)timebar_height);
524 tempo_label.set_alignment (1.0, 0.5);
525 tempo_label.set_padding (5,0);
527 tempo_label.set_no_show_all();
529 meter_label.set_name ("EditorRulerLabel");
530 meter_label.set_size_request (-1, (int)timebar_height);
531 meter_label.set_alignment (1.0, 0.5);
532 meter_label.set_padding (5,0);
534 meter_label.set_no_show_all();
536 if (Profile->get_trx()) {
537 mark_label.set_text (_("Markers"));
539 mark_label.set_name ("EditorRulerLabel");
540 mark_label.set_size_request (-1, (int)timebar_height);
541 mark_label.set_alignment (1.0, 0.5);
542 mark_label.set_padding (5,0);
544 mark_label.set_no_show_all();
546 cd_mark_label.set_name ("EditorRulerLabel");
547 cd_mark_label.set_size_request (-1, (int)timebar_height);
548 cd_mark_label.set_alignment (1.0, 0.5);
549 cd_mark_label.set_padding (5,0);
550 cd_mark_label.hide();
551 cd_mark_label.set_no_show_all();
553 videotl_bar_height = 4;
554 videotl_label.set_name ("EditorRulerLabel");
555 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
556 videotl_label.set_alignment (1.0, 0.5);
557 videotl_label.set_padding (5,0);
558 videotl_label.hide();
559 videotl_label.set_no_show_all();
561 range_mark_label.set_name ("EditorRulerLabel");
562 range_mark_label.set_size_request (-1, (int)timebar_height);
563 range_mark_label.set_alignment (1.0, 0.5);
564 range_mark_label.set_padding (5,0);
565 range_mark_label.hide();
566 range_mark_label.set_no_show_all();
568 transport_mark_label.set_name ("EditorRulerLabel");
569 transport_mark_label.set_size_request (-1, (int)timebar_height);
570 transport_mark_label.set_alignment (1.0, 0.5);
571 transport_mark_label.set_padding (5,0);
572 transport_mark_label.hide();
573 transport_mark_label.set_no_show_all();
575 initialize_canvas ();
577 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
579 _summary = new EditorSummary (this);
581 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
583 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
585 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
586 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
588 edit_controls_vbox.set_spacing (0);
589 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
590 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
592 HBox* h = manage (new HBox);
593 _group_tabs = new EditorGroupTabs (this);
594 if (!ARDOUR::Profile->get_trx()) {
595 h->pack_start (*_group_tabs, PACK_SHRINK);
597 h->pack_start (edit_controls_vbox);
598 controls_layout.add (*h);
600 controls_layout.set_name ("EditControlsBase");
601 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
602 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
603 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
605 _cursors = new MouseCursors;
606 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
607 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
609 /* Push default cursor to ever-present bottom of cursor stack. */
610 push_canvas_cursor(_cursors->grabber);
612 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
614 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
615 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
616 pad_line_1->set_outline_color (0xFF0000FF);
622 edit_packer.set_col_spacings (0);
623 edit_packer.set_row_spacings (0);
624 edit_packer.set_homogeneous (false);
625 edit_packer.set_border_width (0);
626 edit_packer.set_name ("EditorWindow");
628 time_bars_event_box.add (time_bars_vbox);
629 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
630 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
632 /* labels for the time bars */
633 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
635 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
637 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
639 bottom_hbox.set_border_width (2);
640 bottom_hbox.set_spacing (3);
642 _route_groups = new EditorRouteGroups (this);
643 _routes = new EditorRoutes (this);
644 _regions = new EditorRegions (this);
645 _snapshots = new EditorSnapshots (this);
646 _locations = new EditorLocations (this);
647 _time_info_box = new TimeInfoBox ("EditorTimeInfo", true);
649 /* these are static location signals */
651 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
652 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
653 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
655 add_notebook_page (_("Regions"), _regions->widget ());
656 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
657 add_notebook_page (_("Snapshots"), _snapshots->widget ());
658 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
659 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
661 _the_notebook.set_show_tabs (true);
662 _the_notebook.set_scrollable (true);
663 _the_notebook.popup_disable ();
664 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
665 _the_notebook.show_all ();
667 _notebook_shrunk = false;
670 /* Pick up some settings we need to cache, early */
672 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
675 if (settings && (prop = settings->property ("notebook-shrunk"))) {
676 _notebook_shrunk = string_is_affirmative (prop->value ());
679 editor_summary_pane.set_check_divider_position (true);
680 editor_summary_pane.add (edit_packer);
682 Button* summary_arrows_left_left = manage (new Button);
683 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
684 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
685 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
687 Button* summary_arrows_left_right = manage (new Button);
688 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
689 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
690 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
692 VBox* summary_arrows_left = manage (new VBox);
693 summary_arrows_left->pack_start (*summary_arrows_left_left);
694 summary_arrows_left->pack_start (*summary_arrows_left_right);
696 Button* summary_arrows_right_up = manage (new Button);
697 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
698 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
699 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
701 Button* summary_arrows_right_down = manage (new Button);
702 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
703 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
704 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
706 VBox* summary_arrows_right = manage (new VBox);
707 summary_arrows_right->pack_start (*summary_arrows_right_up);
708 summary_arrows_right->pack_start (*summary_arrows_right_down);
710 Frame* summary_frame = manage (new Frame);
711 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
713 summary_frame->add (*_summary);
714 summary_frame->show ();
716 _summary_hbox.pack_start (*summary_arrows_left, false, false);
717 _summary_hbox.pack_start (*summary_frame, true, true);
718 _summary_hbox.pack_start (*summary_arrows_right, false, false);
720 if (!ARDOUR::Profile->get_trx()) {
721 editor_summary_pane.add (_summary_hbox);
724 edit_pane.set_check_divider_position (true);
725 edit_pane.add (editor_summary_pane);
726 if (!ARDOUR::Profile->get_trx()) {
727 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
728 _editor_list_vbox.pack_start (_the_notebook);
729 edit_pane.add (_editor_list_vbox);
730 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
733 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
734 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
741 if (!settings || ((prop = settings->property ("edit-horizontal-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
742 /* initial allocation is 90% to canvas, 10% to notebook */
743 edit_pane.set_divider (0, 0.90);
745 edit_pane.set_divider (0, fract);
748 if (!settings || ((prop = settings->property ("edit-vertical-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
749 /* initial allocation is 90% to canvas, 10% to summary */
750 editor_summary_pane.set_divider (0, 0.90);
753 editor_summary_pane.set_divider (0, fract);
757 global_vpacker.set_spacing (2);
758 global_vpacker.set_border_width (0);
760 //the next three EventBoxes provide the ability for their child widgets to have a background color. That is all.
762 Gtk::EventBox* ebox = manage (new Gtk::EventBox); //a themeable box
763 ebox->set_name("EditorWindow");
764 ebox->add (toolbar_hbox);
766 Gtk::EventBox* epane_box = manage (new Gtkmm2ext::EventBoxExt); //a themeable box
767 epane_box->set_name("EditorWindow");
768 epane_box->add (edit_pane);
770 Gtk::EventBox* epane_box2 = manage (new Gtkmm2ext::EventBoxExt); //a themeable box
771 epane_box2->set_name("EditorWindow");
772 epane_box2->add (global_vpacker);
774 global_vpacker.pack_start (*ebox, false, false);
775 global_vpacker.pack_start (*epane_box, true, true);
776 global_hpacker.pack_start (*epane_box2, true, true);
778 /* need to show the "contents" widget so that notebook will show if tab is switched to
781 global_hpacker.show ();
783 /* register actions now so that set_state() can find them and set toggles/checks etc */
790 _playlist_selector = new PlaylistSelector();
791 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
793 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
797 nudge_forward_button.set_name ("nudge button");
798 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
800 nudge_backward_button.set_name ("nudge button");
801 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
803 fade_context_menu.set_name ("ArdourContextMenu");
805 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
807 /* allow external control surfaces/protocols to do various things */
809 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
810 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
811 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
812 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
813 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
814 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
815 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
816 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
817 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
818 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
819 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
820 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
821 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
822 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
824 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
825 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
826 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
827 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
828 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
830 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
834 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
836 /* problematic: has to return a value and thus cannot be x-thread */
838 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
840 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
841 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
843 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
845 _ignore_region_action = false;
846 _last_region_menu_was_main = false;
847 _popup_region_menu_item = 0;
849 _show_marker_lines = false;
851 /* Button bindings */
853 button_bindings = new Bindings ("editor-mouse");
855 XMLNode* node = button_settings();
857 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
858 button_bindings->load_operation (**i);
864 /* grab current parameter state */
865 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
866 UIConfiguration::instance().map_parameters (pc);
868 setup_fade_images ();
875 delete button_bindings;
877 delete _route_groups;
878 delete _track_canvas_viewport;
881 delete _verbose_cursor;
882 delete quantize_dialog;
888 delete _playlist_selector;
889 delete _time_info_box;
894 LuaInstance::destroy_instance ();
896 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
899 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_in_images.begin(); i != _xfade_in_images.end (); ++i) {
902 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_out_images.begin(); i != _xfade_out_images.end (); ++i) {
908 Editor::button_settings () const
910 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
911 XMLNode* node = find_named_node (*settings, X_("Buttons"));
914 node = new XMLNode (X_("Buttons"));
921 Editor::get_smart_mode () const
923 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
927 Editor::catch_vanishing_regionview (RegionView *rv)
929 /* note: the selection will take care of the vanishing
930 audioregionview by itself.
933 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
937 if (clicked_regionview == rv) {
938 clicked_regionview = 0;
941 if (entered_regionview == rv) {
942 set_entered_regionview (0);
945 if (!_all_region_actions_sensitized) {
946 sensitize_all_region_actions (true);
951 Editor::set_entered_regionview (RegionView* rv)
953 if (rv == entered_regionview) {
957 if (entered_regionview) {
958 entered_regionview->exited ();
961 entered_regionview = rv;
963 if (entered_regionview != 0) {
964 entered_regionview->entered ();
967 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
968 /* This RegionView entry might have changed what region actions
969 are allowed, so sensitize them all in case a key is pressed.
971 sensitize_all_region_actions (true);
976 Editor::set_entered_track (TimeAxisView* tav)
979 entered_track->exited ();
985 entered_track->entered ();
990 Editor::instant_save ()
992 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
997 _session->add_instant_xml(get_state());
999 Config->add_instant_xml(get_state());
1004 Editor::control_vertical_zoom_in_all ()
1006 tav_zoom_smooth (false, true);
1010 Editor::control_vertical_zoom_out_all ()
1012 tav_zoom_smooth (true, true);
1016 Editor::control_vertical_zoom_in_selected ()
1018 tav_zoom_smooth (false, false);
1022 Editor::control_vertical_zoom_out_selected ()
1024 tav_zoom_smooth (true, false);
1028 Editor::control_view (uint32_t view)
1030 goto_visual_state (view);
1034 Editor::control_unselect ()
1036 selection->clear_tracks ();
1040 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1042 TimeAxisView* tav = axis_view_from_stripable (s);
1046 case Selection::Add:
1047 selection->add (tav);
1049 case Selection::Toggle:
1050 selection->toggle (tav);
1052 case Selection::Extend:
1054 case Selection::Set:
1055 selection->set (tav);
1059 selection->clear_tracks ();
1064 Editor::control_step_tracks_up ()
1066 scroll_tracks_up_line ();
1070 Editor::control_step_tracks_down ()
1072 scroll_tracks_down_line ();
1076 Editor::control_scroll (float fraction)
1078 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1084 double step = fraction * current_page_samples();
1087 _control_scroll_target is an optional<T>
1089 it acts like a pointer to an framepos_t, with
1090 a operator conversion to boolean to check
1091 that it has a value could possibly use
1092 playhead_cursor->current_frame to store the
1093 value and a boolean in the class to know
1094 when it's out of date
1097 if (!_control_scroll_target) {
1098 _control_scroll_target = _session->transport_frame();
1099 _dragging_playhead = true;
1102 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1103 *_control_scroll_target = 0;
1104 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1105 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1107 *_control_scroll_target += (framepos_t) trunc (step);
1110 /* move visuals, we'll catch up with it later */
1112 playhead_cursor->set_position (*_control_scroll_target);
1113 UpdateAllTransportClocks (*_control_scroll_target);
1115 if (*_control_scroll_target > (current_page_samples() / 2)) {
1116 /* try to center PH in window */
1117 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1123 Now we do a timeout to actually bring the session to the right place
1124 according to the playhead. This is to avoid reading disk buffers on every
1125 call to control_scroll, which is driven by ScrollTimeline and therefore
1126 probably by a control surface wheel which can generate lots of events.
1128 /* cancel the existing timeout */
1130 control_scroll_connection.disconnect ();
1132 /* add the next timeout */
1134 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1138 Editor::deferred_control_scroll (framepos_t /*target*/)
1140 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1141 // reset for next stream
1142 _control_scroll_target = boost::none;
1143 _dragging_playhead = false;
1148 Editor::access_action (std::string action_group, std::string action_item)
1154 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1157 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1165 Editor::on_realize ()
1169 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1170 start_lock_event_timing ();
1175 Editor::start_lock_event_timing ()
1177 /* check if we should lock the GUI every 30 seconds */
1179 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1183 Editor::generic_event_handler (GdkEvent* ev)
1186 case GDK_BUTTON_PRESS:
1187 case GDK_BUTTON_RELEASE:
1188 case GDK_MOTION_NOTIFY:
1190 case GDK_KEY_RELEASE:
1191 if (contents().is_mapped()) {
1192 gettimeofday (&last_event_time, 0);
1196 case GDK_LEAVE_NOTIFY:
1197 switch (ev->crossing.detail) {
1198 case GDK_NOTIFY_UNKNOWN:
1199 case GDK_NOTIFY_INFERIOR:
1200 case GDK_NOTIFY_ANCESTOR:
1202 case GDK_NOTIFY_VIRTUAL:
1203 case GDK_NOTIFY_NONLINEAR:
1204 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1205 /* leaving window, so reset focus, thus ending any and
1206 all text entry operations.
1208 ARDOUR_UI::instance()->reset_focus (&contents());
1221 Editor::lock_timeout_callback ()
1223 struct timeval now, delta;
1225 gettimeofday (&now, 0);
1227 timersub (&now, &last_event_time, &delta);
1229 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1231 /* don't call again. Returning false will effectively
1232 disconnect us from the timer callback.
1234 unlock() will call start_lock_event_timing() to get things
1244 Editor::map_position_change (framepos_t frame)
1246 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1248 if (_session == 0) {
1252 if (_follow_playhead) {
1253 center_screen (frame);
1256 playhead_cursor->set_position (frame);
1260 Editor::center_screen (framepos_t frame)
1262 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1264 /* if we're off the page, then scroll.
1267 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1268 center_screen_internal (frame, page);
1273 Editor::center_screen_internal (framepos_t frame, float page)
1278 frame -= (framepos_t) page;
1283 reset_x_origin (frame);
1288 Editor::update_title ()
1290 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1292 if (!own_window()) {
1297 bool dirty = _session->dirty();
1299 string session_name;
1301 if (_session->snap_name() != _session->name()) {
1302 session_name = _session->snap_name();
1304 session_name = _session->name();
1308 session_name = "*" + session_name;
1311 WindowTitle title(session_name);
1312 title += S_("Window|Editor");
1313 title += Glib::get_application_name();
1314 own_window()->set_title (title.get_string());
1316 /* ::session_going_away() will have taken care of it */
1321 Editor::set_session (Session *t)
1323 SessionHandlePtr::set_session (t);
1329 _playlist_selector->set_session (_session);
1330 nudge_clock->set_session (_session);
1331 _summary->set_session (_session);
1332 _group_tabs->set_session (_session);
1333 _route_groups->set_session (_session);
1334 _regions->set_session (_session);
1335 _snapshots->set_session (_session);
1336 _routes->set_session (_session);
1337 _locations->set_session (_session);
1338 _time_info_box->set_session (_session);
1340 if (rhythm_ferret) {
1341 rhythm_ferret->set_session (_session);
1344 if (analysis_window) {
1345 analysis_window->set_session (_session);
1349 sfbrowser->set_session (_session);
1352 compute_fixed_ruler_scale ();
1354 /* Make sure we have auto loop and auto punch ranges */
1356 Location* loc = _session->locations()->auto_loop_location();
1358 loc->set_name (_("Loop"));
1361 loc = _session->locations()->auto_punch_location();
1364 loc->set_name (_("Punch"));
1367 refresh_location_display ();
1369 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1370 the selected Marker; this needs the LocationMarker list to be available.
1372 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1373 set_state (*node, Stateful::loading_state_version);
1375 /* catch up with the playhead */
1377 _session->request_locate (playhead_cursor->current_frame ());
1378 _pending_initial_locate = true;
1382 /* These signals can all be emitted by a non-GUI thread. Therefore the
1383 handlers for them must not attempt to directly interact with the GUI,
1384 but use PBD::Signal<T>::connect() which accepts an event loop
1385 ("context") where the handler will be asked to run.
1388 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1389 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1390 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1391 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1392 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1393 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1394 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1395 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1396 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1397 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1398 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1399 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1400 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1401 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1402 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1404 playhead_cursor->show ();
1406 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1407 Config->map_parameters (pc);
1408 _session->config.map_parameters (pc);
1410 restore_ruler_visibility ();
1411 //tempo_map_changed (PropertyChange (0));
1412 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1414 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1415 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1418 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1419 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1422 switch (_snap_type) {
1423 case SnapToRegionStart:
1424 case SnapToRegionEnd:
1425 case SnapToRegionSync:
1426 case SnapToRegionBoundary:
1427 build_region_boundary_cache ();
1434 /* catch up on selection of stripables (other selection state is lost
1435 * when a session is closed
1440 _session->get_stripables (sl);
1441 for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
1442 if ((*s)->presentation_info().selected()) {
1443 RouteTimeAxisView* rtav = get_route_view_by_route_id ((*s)->id());
1445 tl.push_back (rtav);
1450 selection->set (tl);
1453 /* register for undo history */
1454 _session->register_with_memento_command_factory(id(), this);
1455 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1457 LuaInstance::instance()->set_session(_session);
1459 start_updating_meters ();
1463 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1465 using namespace Menu_Helpers;
1467 void (Editor::*emf)(FadeShape);
1468 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1471 images = &_xfade_in_images;
1472 emf = &Editor::set_fade_in_shape;
1474 images = &_xfade_out_images;
1475 emf = &Editor::set_fade_out_shape;
1480 _("Linear (for highly correlated material)"),
1481 *(*images)[FadeLinear],
1482 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1486 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1490 _("Constant power"),
1491 *(*images)[FadeConstantPower],
1492 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1495 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1500 *(*images)[FadeSymmetric],
1501 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1505 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1510 *(*images)[FadeSlow],
1511 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1514 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1519 *(*images)[FadeFast],
1520 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1523 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1526 /** Pop up a context menu for when the user clicks on a start crossfade */
1528 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1530 using namespace Menu_Helpers;
1531 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1536 MenuList& items (xfade_in_context_menu.items());
1539 if (arv->audio_region()->fade_in_active()) {
1540 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1542 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1545 items.push_back (SeparatorElem());
1546 fill_xfade_menu (items, true);
1548 xfade_in_context_menu.popup (button, time);
1551 /** Pop up a context menu for when the user clicks on an end crossfade */
1553 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1555 using namespace Menu_Helpers;
1556 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1561 MenuList& items (xfade_out_context_menu.items());
1564 if (arv->audio_region()->fade_out_active()) {
1565 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1567 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1570 items.push_back (SeparatorElem());
1571 fill_xfade_menu (items, false);
1573 xfade_out_context_menu.popup (button, time);
1577 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1579 using namespace Menu_Helpers;
1580 Menu* (Editor::*build_menu_function)();
1583 switch (item_type) {
1585 case RegionViewName:
1586 case RegionViewNameHighlight:
1587 case LeftFrameHandle:
1588 case RightFrameHandle:
1589 if (with_selection) {
1590 build_menu_function = &Editor::build_track_selection_context_menu;
1592 build_menu_function = &Editor::build_track_region_context_menu;
1597 if (with_selection) {
1598 build_menu_function = &Editor::build_track_selection_context_menu;
1600 build_menu_function = &Editor::build_track_context_menu;
1605 if (clicked_routeview->track()) {
1606 build_menu_function = &Editor::build_track_context_menu;
1608 build_menu_function = &Editor::build_track_bus_context_menu;
1613 /* probably shouldn't happen but if it does, we don't care */
1617 menu = (this->*build_menu_function)();
1618 menu->set_name ("ArdourContextMenu");
1620 /* now handle specific situations */
1622 switch (item_type) {
1624 case RegionViewName:
1625 case RegionViewNameHighlight:
1626 case LeftFrameHandle:
1627 case RightFrameHandle:
1628 if (!with_selection) {
1629 if (region_edit_menu_split_item) {
1630 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1631 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1633 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1636 if (region_edit_menu_split_multichannel_item) {
1637 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1638 region_edit_menu_split_multichannel_item->set_sensitive (true);
1640 region_edit_menu_split_multichannel_item->set_sensitive (false);
1653 /* probably shouldn't happen but if it does, we don't care */
1657 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1659 /* Bounce to disk */
1661 using namespace Menu_Helpers;
1662 MenuList& edit_items = menu->items();
1664 edit_items.push_back (SeparatorElem());
1666 switch (clicked_routeview->audio_track()->freeze_state()) {
1667 case AudioTrack::NoFreeze:
1668 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1671 case AudioTrack::Frozen:
1672 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1675 case AudioTrack::UnFrozen:
1676 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1682 if (item_type == StreamItem && clicked_routeview) {
1683 clicked_routeview->build_underlay_menu(menu);
1686 /* When the region menu is opened, we setup the actions so that they look right
1689 sensitize_the_right_region_actions (false);
1690 _last_region_menu_was_main = false;
1692 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1693 menu->popup (button, time);
1697 Editor::build_track_context_menu ()
1699 using namespace Menu_Helpers;
1701 MenuList& edit_items = track_context_menu.items();
1704 add_dstream_context_items (edit_items);
1705 return &track_context_menu;
1709 Editor::build_track_bus_context_menu ()
1711 using namespace Menu_Helpers;
1713 MenuList& edit_items = track_context_menu.items();
1716 add_bus_context_items (edit_items);
1717 return &track_context_menu;
1721 Editor::build_track_region_context_menu ()
1723 using namespace Menu_Helpers;
1724 MenuList& edit_items = track_region_context_menu.items();
1727 /* we've just cleared the track region context menu, so the menu that these
1728 two items were on will have disappeared; stop them dangling.
1730 region_edit_menu_split_item = 0;
1731 region_edit_menu_split_multichannel_item = 0;
1733 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1736 boost::shared_ptr<Track> tr;
1737 boost::shared_ptr<Playlist> pl;
1739 if ((tr = rtv->track())) {
1740 add_region_context_items (edit_items, tr);
1744 add_dstream_context_items (edit_items);
1746 return &track_region_context_menu;
1750 Editor::loudness_analyze_region_selection ()
1755 Selection& s (PublicEditor::instance ().get_selection ());
1756 RegionSelection ars = s.regions;
1757 ARDOUR::AnalysisGraph ag (_session);
1758 framecnt_t total_work = 0;
1760 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1761 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1765 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1768 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1769 total_work += arv->region ()->length ();
1772 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1774 ag.set_total_frames (total_work);
1775 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1778 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1779 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1783 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1787 ag.analyze_region (ar);
1790 if (!ag.canceled ()) {
1791 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1797 Editor::loudness_analyze_range_selection ()
1802 Selection& s (PublicEditor::instance ().get_selection ());
1803 TimeSelection ts = s.time;
1804 ARDOUR::AnalysisGraph ag (_session);
1805 framecnt_t total_work = 0;
1807 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1808 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1812 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1816 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1817 total_work += j->length ();
1821 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1823 ag.set_total_frames (total_work);
1824 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1827 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1828 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1832 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1836 ag.analyze_range (rui->route (), pl, ts);
1839 if (!ag.canceled ()) {
1840 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1846 Editor::spectral_analyze_region_selection ()
1848 if (analysis_window == 0) {
1849 analysis_window = new AnalysisWindow();
1852 analysis_window->set_session(_session);
1854 analysis_window->show_all();
1857 analysis_window->set_regionmode();
1858 analysis_window->analyze();
1860 analysis_window->present();
1864 Editor::spectral_analyze_range_selection()
1866 if (analysis_window == 0) {
1867 analysis_window = new AnalysisWindow();
1870 analysis_window->set_session(_session);
1872 analysis_window->show_all();
1875 analysis_window->set_rangemode();
1876 analysis_window->analyze();
1878 analysis_window->present();
1882 Editor::build_track_selection_context_menu ()
1884 using namespace Menu_Helpers;
1885 MenuList& edit_items = track_selection_context_menu.items();
1886 edit_items.clear ();
1888 add_selection_context_items (edit_items);
1889 // edit_items.push_back (SeparatorElem());
1890 // add_dstream_context_items (edit_items);
1892 return &track_selection_context_menu;
1896 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1898 using namespace Menu_Helpers;
1900 /* OK, stick the region submenu at the top of the list, and then add
1904 RegionSelection rs = get_regions_from_selection_and_entered ();
1906 string::size_type pos = 0;
1907 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1909 /* we have to hack up the region name because "_" has a special
1910 meaning for menu titles.
1913 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1914 menu_item_name.replace (pos, 1, "__");
1918 if (_popup_region_menu_item == 0) {
1919 _popup_region_menu_item = new MenuItem (menu_item_name);
1920 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1921 _popup_region_menu_item->show ();
1923 _popup_region_menu_item->set_label (menu_item_name);
1926 /* No layering allowed in later is higher layering model */
1927 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1928 if (act && Config->get_layer_model() == LaterHigher) {
1929 act->set_sensitive (false);
1931 act->set_sensitive (true);
1934 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1936 edit_items.push_back (*_popup_region_menu_item);
1937 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1938 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1940 edit_items.push_back (SeparatorElem());
1943 /** Add context menu items relevant to selection ranges.
1944 * @param edit_items List to add the items to.
1947 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1949 using namespace Menu_Helpers;
1951 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1952 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1954 edit_items.push_back (SeparatorElem());
1955 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1957 edit_items.push_back (SeparatorElem());
1958 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1959 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1961 edit_items.push_back (SeparatorElem());
1963 edit_items.push_back (
1965 _("Move Range Start to Previous Region Boundary"),
1966 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1970 edit_items.push_back (
1972 _("Move Range Start to Next Region Boundary"),
1973 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1977 edit_items.push_back (
1979 _("Move Range End to Previous Region Boundary"),
1980 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1984 edit_items.push_back (
1986 _("Move Range End to Next Region Boundary"),
1987 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1991 edit_items.push_back (SeparatorElem());
1992 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1993 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1995 edit_items.push_back (SeparatorElem());
1996 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1998 edit_items.push_back (SeparatorElem());
1999 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
2000 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
2001 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
2003 edit_items.push_back (SeparatorElem());
2004 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
2006 edit_items.push_back (SeparatorElem());
2007 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
2008 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
2010 edit_items.push_back (SeparatorElem());
2011 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
2012 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
2013 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
2014 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
2015 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
2016 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
2017 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2023 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2025 using namespace Menu_Helpers;
2029 Menu *play_menu = manage (new Menu);
2030 MenuList& play_items = play_menu->items();
2031 play_menu->set_name ("ArdourContextMenu");
2033 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2034 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2035 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2036 play_items.push_back (SeparatorElem());
2037 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2039 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2043 Menu *select_menu = manage (new Menu);
2044 MenuList& select_items = select_menu->items();
2045 select_menu->set_name ("ArdourContextMenu");
2047 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2048 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2049 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2050 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2051 select_items.push_back (SeparatorElem());
2052 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2053 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2054 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2055 select_items.push_back (SeparatorElem());
2056 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2057 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2058 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2059 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2060 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2061 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2062 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2064 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2068 Menu *cutnpaste_menu = manage (new Menu);
2069 MenuList& cutnpaste_items = cutnpaste_menu->items();
2070 cutnpaste_menu->set_name ("ArdourContextMenu");
2072 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2073 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2074 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2076 cutnpaste_items.push_back (SeparatorElem());
2078 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2079 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2081 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2083 /* Adding new material */
2085 edit_items.push_back (SeparatorElem());
2086 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2087 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2091 Menu *nudge_menu = manage (new Menu());
2092 MenuList& nudge_items = nudge_menu->items();
2093 nudge_menu->set_name ("ArdourContextMenu");
2095 edit_items.push_back (SeparatorElem());
2096 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2097 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2098 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2099 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2101 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2105 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2107 using namespace Menu_Helpers;
2111 Menu *play_menu = manage (new Menu);
2112 MenuList& play_items = play_menu->items();
2113 play_menu->set_name ("ArdourContextMenu");
2115 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2116 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2117 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2121 Menu *select_menu = manage (new Menu);
2122 MenuList& select_items = select_menu->items();
2123 select_menu->set_name ("ArdourContextMenu");
2125 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2126 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2127 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2128 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2129 select_items.push_back (SeparatorElem());
2130 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2131 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2132 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2133 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2135 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2139 Menu *cutnpaste_menu = manage (new Menu);
2140 MenuList& cutnpaste_items = cutnpaste_menu->items();
2141 cutnpaste_menu->set_name ("ArdourContextMenu");
2143 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2144 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2145 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2147 Menu *nudge_menu = manage (new Menu());
2148 MenuList& nudge_items = nudge_menu->items();
2149 nudge_menu->set_name ("ArdourContextMenu");
2151 edit_items.push_back (SeparatorElem());
2152 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2153 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2154 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2155 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2157 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2161 Editor::snap_type() const
2167 Editor::snap_musical() const
2169 switch (_snap_type) {
2170 case SnapToBeatDiv128:
2171 case SnapToBeatDiv64:
2172 case SnapToBeatDiv32:
2173 case SnapToBeatDiv28:
2174 case SnapToBeatDiv24:
2175 case SnapToBeatDiv20:
2176 case SnapToBeatDiv16:
2177 case SnapToBeatDiv14:
2178 case SnapToBeatDiv12:
2179 case SnapToBeatDiv10:
2180 case SnapToBeatDiv8:
2181 case SnapToBeatDiv7:
2182 case SnapToBeatDiv6:
2183 case SnapToBeatDiv5:
2184 case SnapToBeatDiv4:
2185 case SnapToBeatDiv3:
2186 case SnapToBeatDiv2:
2198 Editor::snap_mode() const
2204 Editor::set_snap_to (SnapType st)
2206 unsigned int snap_ind = (unsigned int)st;
2208 if (internal_editing()) {
2209 internal_snap_type = st;
2211 pre_internal_snap_type = st;
2216 if (snap_ind > snap_type_strings.size() - 1) {
2218 _snap_type = (SnapType)snap_ind;
2221 string str = snap_type_strings[snap_ind];
2223 if (str != snap_type_selector.get_text()) {
2224 snap_type_selector.set_text (str);
2229 switch (_snap_type) {
2230 case SnapToBeatDiv128:
2231 case SnapToBeatDiv64:
2232 case SnapToBeatDiv32:
2233 case SnapToBeatDiv28:
2234 case SnapToBeatDiv24:
2235 case SnapToBeatDiv20:
2236 case SnapToBeatDiv16:
2237 case SnapToBeatDiv14:
2238 case SnapToBeatDiv12:
2239 case SnapToBeatDiv10:
2240 case SnapToBeatDiv8:
2241 case SnapToBeatDiv7:
2242 case SnapToBeatDiv6:
2243 case SnapToBeatDiv5:
2244 case SnapToBeatDiv4:
2245 case SnapToBeatDiv3:
2246 case SnapToBeatDiv2: {
2247 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
2248 update_tempo_based_rulers ();
2252 case SnapToRegionStart:
2253 case SnapToRegionEnd:
2254 case SnapToRegionSync:
2255 case SnapToRegionBoundary:
2256 build_region_boundary_cache ();
2264 redisplay_tempo (false);
2266 SnapChanged (); /* EMIT SIGNAL */
2270 Editor::set_snap_mode (SnapMode mode)
2272 string str = snap_mode_strings[(int)mode];
2274 if (internal_editing()) {
2275 internal_snap_mode = mode;
2277 pre_internal_snap_mode = mode;
2282 if (str != snap_mode_selector.get_text ()) {
2283 snap_mode_selector.set_text (str);
2290 Editor::set_edit_point_preference (EditPoint ep, bool force)
2292 bool changed = (_edit_point != ep);
2295 if (Profile->get_mixbus())
2296 if (ep == EditAtSelectedMarker)
2297 ep = EditAtPlayhead;
2299 string str = edit_point_strings[(int)ep];
2300 if (str != edit_point_selector.get_text ()) {
2301 edit_point_selector.set_text (str);
2304 update_all_enter_cursors();
2306 if (!force && !changed) {
2310 const char* action=NULL;
2312 switch (_edit_point) {
2313 case EditAtPlayhead:
2314 action = "edit-at-playhead";
2316 case EditAtSelectedMarker:
2317 action = "edit-at-marker";
2320 action = "edit-at-mouse";
2324 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2326 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2330 bool in_track_canvas;
2332 if (!mouse_frame (foo, in_track_canvas)) {
2333 in_track_canvas = false;
2336 reset_canvas_action_sensitivity (in_track_canvas);
2337 sensitize_the_right_region_actions (false);
2343 Editor::set_state (const XMLNode& node, int version)
2345 XMLProperty const * prop;
2347 PBD::Unwinder<bool> nsi (no_save_instant, true);
2350 Tabbable::set_state (node, version);
2352 if (_session && (prop = node.property ("playhead"))) {
2354 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2356 playhead_cursor->set_position (pos);
2358 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2359 playhead_cursor->set_position (0);
2362 playhead_cursor->set_position (0);
2365 if ((prop = node.property ("mixer-width"))) {
2366 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2369 if ((prop = node.property ("zoom-focus"))) {
2370 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2372 zoom_focus_selection_done (zoom_focus);
2375 if ((prop = node.property ("zoom"))) {
2376 /* older versions of ardour used floating point samples_per_pixel */
2377 double f = PBD::atof (prop->value());
2378 reset_zoom (llrintf (f));
2380 reset_zoom (samples_per_pixel);
2383 if ((prop = node.property ("visible-track-count"))) {
2384 set_visible_track_count (PBD::atoi (prop->value()));
2387 if ((prop = node.property ("snap-to"))) {
2388 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2389 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2391 set_snap_to (_snap_type);
2394 if ((prop = node.property ("snap-mode"))) {
2395 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2396 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2397 * snap_mode_selection_done() will only mark an already active item as active
2398 * which does not trigger set_text().
2400 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2402 set_snap_mode (_snap_mode);
2405 if ((prop = node.property ("internal-snap-to"))) {
2406 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2409 if ((prop = node.property ("internal-snap-mode"))) {
2410 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2413 if ((prop = node.property ("pre-internal-snap-to"))) {
2414 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2417 if ((prop = node.property ("pre-internal-snap-mode"))) {
2418 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2421 if ((prop = node.property ("mouse-mode"))) {
2422 MouseMode m = str2mousemode(prop->value());
2423 set_mouse_mode (m, true);
2425 set_mouse_mode (MouseObject, true);
2428 if ((prop = node.property ("left-frame")) != 0) {
2430 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2434 reset_x_origin (pos);
2438 if ((prop = node.property ("y-origin")) != 0) {
2439 reset_y_origin (atof (prop->value ()));
2442 if ((prop = node.property ("join-object-range"))) {
2443 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2444 bool yn = string_is_affirmative (prop->value());
2446 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2447 tact->set_active (!yn);
2448 tact->set_active (yn);
2450 set_mouse_mode(mouse_mode, true);
2453 if ((prop = node.property ("edit-point"))) {
2454 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2456 set_edit_point_preference (_edit_point);
2459 if ((prop = node.property ("show-measures"))) {
2460 bool yn = string_is_affirmative (prop->value());
2461 _show_measures = yn;
2464 if ((prop = node.property ("follow-playhead"))) {
2465 bool yn = string_is_affirmative (prop->value());
2466 set_follow_playhead (yn);
2469 if ((prop = node.property ("stationary-playhead"))) {
2470 bool yn = string_is_affirmative (prop->value());
2471 set_stationary_playhead (yn);
2474 if ((prop = node.property ("region-list-sort-type"))) {
2475 RegionListSortType st;
2476 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2479 if ((prop = node.property ("show-editor-mixer"))) {
2481 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2484 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2485 bool yn = string_is_affirmative (prop->value());
2487 /* do it twice to force the change */
2489 tact->set_active (!yn);
2490 tact->set_active (yn);
2493 if ((prop = node.property ("show-editor-list"))) {
2495 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2498 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2499 bool yn = string_is_affirmative (prop->value());
2501 /* do it twice to force the change */
2503 tact->set_active (!yn);
2504 tact->set_active (yn);
2507 if ((prop = node.property (X_("editor-list-page")))) {
2508 _the_notebook.set_current_page (atoi (prop->value ()));
2511 if ((prop = node.property (X_("show-marker-lines")))) {
2512 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2514 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2515 bool yn = string_is_affirmative (prop->value ());
2517 tact->set_active (!yn);
2518 tact->set_active (yn);
2521 XMLNodeList children = node.children ();
2522 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2523 selection->set_state (**i, Stateful::current_state_version);
2524 _regions->set_state (**i);
2525 _locations->set_state (**i);
2528 if ((prop = node.property ("maximised"))) {
2529 bool yn = string_is_affirmative (prop->value());
2530 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2532 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2533 bool fs = tact && tact->get_active();
2535 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2539 if ((prop = node.property ("nudge-clock-value"))) {
2541 sscanf (prop->value().c_str(), "%" PRId64, &f);
2542 nudge_clock->set (f);
2544 nudge_clock->set_mode (AudioClock::Timecode);
2545 nudge_clock->set (_session->frame_rate() * 5, true);
2550 * Not all properties may have been in XML, but
2551 * those that are linked to a private variable may need changing
2556 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2558 yn = _show_measures;
2559 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2560 /* do it twice to force the change */
2561 tact->set_active (!yn);
2562 tact->set_active (yn);
2565 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2566 yn = _follow_playhead;
2568 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2569 if (tact->get_active() != yn) {
2570 tact->set_active (yn);
2574 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2575 yn = _stationary_playhead;
2577 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2578 if (tact->get_active() != yn) {
2579 tact->set_active (yn);
2584 return LuaInstance::instance()->set_state(node);
2588 Editor::get_state ()
2590 XMLNode* node = new XMLNode (X_("Editor"));
2594 id().print (buf, sizeof (buf));
2595 node->add_property ("id", buf);
2597 node->add_child_nocopy (Tabbable::get_state());
2599 snprintf(buf,sizeof(buf), "%f", edit_pane.get_divider ());
2600 node->add_property("edit-horizontal-pane-pos", string(buf));
2601 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2602 snprintf(buf,sizeof(buf), "%f", editor_summary_pane.get_divider());
2603 node->add_property("edit-vertical-pane-pos", string(buf));
2605 maybe_add_mixer_strip_width (*node);
2607 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2609 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2610 node->add_property ("zoom", buf);
2611 node->add_property ("snap-to", enum_2_string (_snap_type));
2612 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2613 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2614 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2615 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2616 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2617 node->add_property ("edit-point", enum_2_string (_edit_point));
2618 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2619 node->add_property ("visible-track-count", buf);
2621 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2622 node->add_property ("playhead", buf);
2623 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2624 node->add_property ("left-frame", buf);
2625 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2626 node->add_property ("y-origin", buf);
2628 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2629 node->add_property ("maximised", _maximised ? "yes" : "no");
2630 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2631 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2632 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2633 node->add_property ("mouse-mode", enum2str(mouse_mode));
2634 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2636 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2638 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2639 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2642 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2644 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2645 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2648 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2649 node->add_property (X_("editor-list-page"), buf);
2651 if (button_bindings) {
2652 XMLNode* bb = new XMLNode (X_("Buttons"));
2653 button_bindings->save (*bb);
2654 node->add_child_nocopy (*bb);
2657 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2659 node->add_child_nocopy (selection->get_state ());
2660 node->add_child_nocopy (_regions->get_state ());
2662 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2663 node->add_property ("nudge-clock-value", buf);
2665 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2666 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2667 node->add_child_nocopy (_locations->get_state ());
2672 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2673 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2675 * @return pair: TimeAxisView that y is over, layer index.
2677 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2678 * in stacked or expanded region display mode, otherwise 0.
2680 std::pair<TimeAxisView *, double>
2681 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2683 if (!trackview_relative_offset) {
2684 y -= _trackview_group->canvas_origin().y;
2688 return std::make_pair ( (TimeAxisView *) 0, 0);
2691 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2693 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2700 return std::make_pair ( (TimeAxisView *) 0, 0);
2703 /** Snap a position to the grid, if appropriate, taking into account current
2704 * grid settings and also the state of any snap modifier keys that may be pressed.
2705 * @param start Position to snap.
2706 * @param event Event to get current key modifier information from, or 0.
2709 Editor::snap_to_with_modifier (MusicFrame& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2711 if (!_session || !event) {
2715 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2716 if (_snap_mode == SnapOff) {
2717 snap_to_internal (start, direction, for_mark);
2719 start.set (start.frame, 0);
2722 if (_snap_mode != SnapOff) {
2723 snap_to_internal (start, direction, for_mark);
2724 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2725 /* SnapOff, but we pressed the snap_delta modifier */
2726 snap_to_internal (start, direction, for_mark);
2728 start.set (start.frame, 0);
2734 Editor::snap_to (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap)
2736 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2737 start.set (start.frame, 0);
2741 snap_to_internal (start, direction, for_mark, ensure_snap);
2745 Editor::timecode_snap_to_internal (MusicFrame& pos, RoundMode direction, bool /*for_mark*/)
2747 framepos_t start = pos.frame;
2748 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2749 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2751 switch (_snap_type) {
2752 case SnapToTimecodeFrame:
2753 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2754 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2755 /* start is already on a whole timecode frame, do nothing */
2756 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2757 start = (framepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2759 start = (framepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2763 case SnapToTimecodeSeconds:
2764 if (_session->config.get_timecode_offset_negative()) {
2765 start += _session->config.get_timecode_offset ();
2767 start -= _session->config.get_timecode_offset ();
2769 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2770 (start % one_timecode_second == 0)) {
2771 /* start is already on a whole second, do nothing */
2772 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2773 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2775 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2778 if (_session->config.get_timecode_offset_negative()) {
2779 start -= _session->config.get_timecode_offset ();
2781 start += _session->config.get_timecode_offset ();
2785 case SnapToTimecodeMinutes:
2786 if (_session->config.get_timecode_offset_negative()) {
2787 start += _session->config.get_timecode_offset ();
2789 start -= _session->config.get_timecode_offset ();
2791 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2792 (start % one_timecode_minute == 0)) {
2793 /* start is already on a whole minute, do nothing */
2794 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2795 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2797 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2799 if (_session->config.get_timecode_offset_negative()) {
2800 start -= _session->config.get_timecode_offset ();
2802 start += _session->config.get_timecode_offset ();
2806 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2807 abort(); /*NOTREACHED*/
2814 Editor::snap_to_internal (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap)
2816 const framepos_t one_second = _session->frame_rate();
2817 const framepos_t one_minute = _session->frame_rate() * 60;
2818 framepos_t presnap = start.frame;
2822 switch (_snap_type) {
2823 case SnapToTimecodeFrame:
2824 case SnapToTimecodeSeconds:
2825 case SnapToTimecodeMinutes:
2826 return timecode_snap_to_internal (start, direction, for_mark);
2829 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2830 start.frame % (one_second/75) == 0) {
2831 /* start is already on a whole CD frame, do nothing */
2832 } else if (((direction == 0) && (start.frame % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2833 start.frame = (framepos_t) ceil ((double) start.frame / (one_second / 75)) * (one_second / 75);
2835 start.frame = (framepos_t) floor ((double) start.frame / (one_second / 75)) * (one_second / 75);
2838 start.set (start.frame, 0);
2843 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2844 start.frame % one_second == 0) {
2845 /* start is already on a whole second, do nothing */
2846 } else if (((direction == 0) && (start.frame % one_second > one_second / 2)) || (direction > 0)) {
2847 start.frame = (framepos_t) ceil ((double) start.frame / one_second) * one_second;
2849 start.frame = (framepos_t) floor ((double) start.frame / one_second) * one_second;
2852 start.set (start.frame, 0);
2857 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2858 start.frame % one_minute == 0) {
2859 /* start is already on a whole minute, do nothing */
2860 } else if (((direction == 0) && (start.frame % one_minute > one_minute / 2)) || (direction > 0)) {
2861 start.frame = (framepos_t) ceil ((double) start.frame / one_minute) * one_minute;
2863 start.frame = (framepos_t) floor ((double) start.frame / one_minute) * one_minute;
2866 start.set (start.frame, 0);
2871 start = _session->tempo_map().round_to_bar (start.frame, direction);
2875 start = _session->tempo_map().round_to_beat (start.frame, direction);
2878 case SnapToBeatDiv128:
2879 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 128, direction);
2881 case SnapToBeatDiv64:
2882 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 64, direction);
2884 case SnapToBeatDiv32:
2885 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 32, direction);
2887 case SnapToBeatDiv28:
2888 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 28, direction);
2890 case SnapToBeatDiv24:
2891 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 24, direction);
2893 case SnapToBeatDiv20:
2894 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 20, direction);
2896 case SnapToBeatDiv16:
2897 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 16, direction);
2899 case SnapToBeatDiv14:
2900 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 14, direction);
2902 case SnapToBeatDiv12:
2903 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 12, direction);
2905 case SnapToBeatDiv10:
2906 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 10, direction);
2908 case SnapToBeatDiv8:
2909 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 8, direction);
2911 case SnapToBeatDiv7:
2912 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 7, direction);
2914 case SnapToBeatDiv6:
2915 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 6, direction);
2917 case SnapToBeatDiv5:
2918 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 5, direction);
2920 case SnapToBeatDiv4:
2921 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 4, direction);
2923 case SnapToBeatDiv3:
2924 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 3, direction);
2926 case SnapToBeatDiv2:
2927 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 2, direction);
2935 _session->locations()->marks_either_side (start.frame, before, after);
2937 if (before == max_framepos && after == max_framepos) {
2938 /* No marks to snap to, so just don't snap */
2940 } else if (before == max_framepos) {
2941 start.frame = after;
2942 } else if (after == max_framepos) {
2943 start.frame = before;
2944 } else if (before != max_framepos && after != max_framepos) {
2945 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2946 start.frame = after;
2947 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2948 start.frame = before;
2949 else if (direction == 0 ) {
2950 if ((start.frame - before) < (after - start.frame)) {
2951 start.frame = before;
2953 start.frame = after;
2958 start.set (start.frame, 0);
2962 case SnapToRegionStart:
2963 case SnapToRegionEnd:
2964 case SnapToRegionSync:
2965 case SnapToRegionBoundary:
2966 if (!region_boundary_cache.empty()) {
2968 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2969 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2971 if (direction > 0) {
2972 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame);
2974 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame);
2977 if (next != region_boundary_cache.begin ()) {
2982 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2983 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2985 if (start.frame > (p + n) / 2) {
2992 start.set (start.frame, 0);
2997 switch (_snap_mode) {
3007 if (presnap > start.frame) {
3008 if (presnap > (start.frame + pixel_to_sample(snap_threshold))) {
3009 start.set (presnap, 0);
3012 } else if (presnap < start.frame) {
3013 if (presnap < (start.frame - pixel_to_sample(snap_threshold))) {
3014 start.set (presnap, 0);
3019 /* handled at entry */
3026 Editor::setup_toolbar ()
3028 HBox* mode_box = manage(new HBox);
3029 mode_box->set_border_width (2);
3030 mode_box->set_spacing(2);
3032 HBox* mouse_mode_box = manage (new HBox);
3033 HBox* mouse_mode_hbox = manage (new HBox);
3034 VBox* mouse_mode_vbox = manage (new VBox);
3035 Alignment* mouse_mode_align = manage (new Alignment);
3037 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3038 mouse_mode_size_group->add_widget (smart_mode_button);
3039 mouse_mode_size_group->add_widget (mouse_move_button);
3040 mouse_mode_size_group->add_widget (mouse_cut_button);
3041 mouse_mode_size_group->add_widget (mouse_select_button);
3042 mouse_mode_size_group->add_widget (mouse_timefx_button);
3043 mouse_mode_size_group->add_widget (mouse_audition_button);
3044 mouse_mode_size_group->add_widget (mouse_draw_button);
3045 mouse_mode_size_group->add_widget (mouse_content_button);
3047 if (!Profile->get_mixbus()) {
3048 mouse_mode_size_group->add_widget (zoom_in_button);
3049 mouse_mode_size_group->add_widget (zoom_out_button);
3050 mouse_mode_size_group->add_widget (zoom_out_full_button);
3051 mouse_mode_size_group->add_widget (zoom_focus_selector);
3052 mouse_mode_size_group->add_widget (tav_shrink_button);
3053 mouse_mode_size_group->add_widget (tav_expand_button);
3055 mouse_mode_size_group->add_widget (zoom_preset_selector);
3056 mouse_mode_size_group->add_widget (visible_tracks_selector);
3059 mouse_mode_size_group->add_widget (snap_type_selector);
3060 mouse_mode_size_group->add_widget (snap_mode_selector);
3062 mouse_mode_size_group->add_widget (edit_point_selector);
3063 mouse_mode_size_group->add_widget (edit_mode_selector);
3065 mouse_mode_size_group->add_widget (*nudge_clock);
3066 mouse_mode_size_group->add_widget (nudge_forward_button);
3067 mouse_mode_size_group->add_widget (nudge_backward_button);
3069 mouse_mode_hbox->set_spacing (2);
3071 if (!ARDOUR::Profile->get_trx()) {
3072 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3075 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3076 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3078 if (!ARDOUR::Profile->get_mixbus()) {
3079 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3082 if (!ARDOUR::Profile->get_trx()) {
3083 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3084 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3085 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3086 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3089 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3091 mouse_mode_align->add (*mouse_mode_vbox);
3092 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3094 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3096 edit_mode_selector.set_name ("mouse mode button");
3098 if (!ARDOUR::Profile->get_trx()) {
3099 mode_box->pack_start (edit_mode_selector, false, false);
3102 mode_box->pack_start (*mouse_mode_box, false, false);
3106 _zoom_box.set_spacing (2);
3107 _zoom_box.set_border_width (2);
3111 zoom_preset_selector.set_name ("zoom button");
3112 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
3114 zoom_in_button.set_name ("zoom button");
3115 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3116 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3117 zoom_in_button.set_related_action (act);
3119 zoom_out_button.set_name ("zoom button");
3120 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3121 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3122 zoom_out_button.set_related_action (act);
3124 zoom_out_full_button.set_name ("zoom button");
3125 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3126 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3127 zoom_out_full_button.set_related_action (act);
3129 zoom_focus_selector.set_name ("zoom button");
3131 if (ARDOUR::Profile->get_mixbus()) {
3132 _zoom_box.pack_start (zoom_preset_selector, false, false);
3133 } else if (ARDOUR::Profile->get_trx()) {
3134 mode_box->pack_start (zoom_out_button, false, false);
3135 mode_box->pack_start (zoom_in_button, false, false);
3137 _zoom_box.pack_start (zoom_out_button, false, false);
3138 _zoom_box.pack_start (zoom_in_button, false, false);
3139 _zoom_box.pack_start (zoom_out_full_button, false, false);
3140 _zoom_box.pack_start (zoom_focus_selector, false, false);
3143 /* Track zoom buttons */
3144 _track_box.set_spacing (2);
3145 _track_box.set_border_width (2);
3147 visible_tracks_selector.set_name ("zoom button");
3148 if (Profile->get_mixbus()) {
3149 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3151 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3154 tav_expand_button.set_name ("zoom button");
3155 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3156 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3157 tav_expand_button.set_related_action (act);
3159 tav_shrink_button.set_name ("zoom button");
3160 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3161 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3162 tav_shrink_button.set_related_action (act);
3164 if (ARDOUR::Profile->get_mixbus()) {
3165 _track_box.pack_start (visible_tracks_selector);
3166 } else if (ARDOUR::Profile->get_trx()) {
3167 _track_box.pack_start (tav_shrink_button);
3168 _track_box.pack_start (tav_expand_button);
3170 _track_box.pack_start (visible_tracks_selector);
3171 _track_box.pack_start (tav_shrink_button);
3172 _track_box.pack_start (tav_expand_button);
3175 snap_box.set_spacing (2);
3176 snap_box.set_border_width (2);
3178 snap_type_selector.set_name ("mouse mode button");
3180 snap_mode_selector.set_name ("mouse mode button");
3182 edit_point_selector.set_name ("mouse mode button");
3184 snap_box.pack_start (snap_mode_selector, false, false);
3185 snap_box.pack_start (snap_type_selector, false, false);
3188 HBox *ep_box = manage (new HBox);
3189 ep_box->set_spacing (2);
3190 ep_box->set_border_width (2);
3192 ep_box->pack_start (edit_point_selector, false, false);
3196 HBox *nudge_box = manage (new HBox);
3197 nudge_box->set_spacing (2);
3198 nudge_box->set_border_width (2);
3200 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3201 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3203 nudge_box->pack_start (nudge_backward_button, false, false);
3204 nudge_box->pack_start (nudge_forward_button, false, false);
3205 nudge_box->pack_start (*nudge_clock, false, false);
3208 /* Pack everything in... */
3210 toolbar_hbox.set_spacing (2);
3211 toolbar_hbox.set_border_width (2);
3213 toolbar_hbox.pack_start (*mode_box, false, false);
3215 if (!ARDOUR::Profile->get_trx()) {
3217 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3219 toolbar_hbox.pack_start (_zoom_box, false, false);
3221 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3223 toolbar_hbox.pack_start (_track_box, false, false);
3225 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3227 toolbar_hbox.pack_start (snap_box, false, false);
3229 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3231 toolbar_hbox.pack_start (*ep_box, false, false);
3233 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3235 toolbar_hbox.pack_start (*nudge_box, false, false);
3238 toolbar_hbox.show_all ();
3242 Editor::build_edit_point_menu ()
3244 using namespace Menu_Helpers;
3246 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3247 if(!Profile->get_mixbus())
3248 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3249 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3251 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3255 Editor::build_edit_mode_menu ()
3257 using namespace Menu_Helpers;
3259 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3260 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3261 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3262 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3264 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3268 Editor::build_snap_mode_menu ()
3270 using namespace Menu_Helpers;
3272 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3273 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3274 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3276 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3280 Editor::build_snap_type_menu ()
3282 using namespace Menu_Helpers;
3284 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3285 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3286 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3287 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3288 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3289 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3290 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3291 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3292 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3293 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3294 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3295 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3296 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3297 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3298 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3299 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3300 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3301 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3302 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3303 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3304 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3305 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3306 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3307 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3308 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3309 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3310 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3311 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3312 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3313 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3315 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3320 Editor::setup_tooltips ()
3322 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3323 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3324 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3325 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3326 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3327 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3328 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3329 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3330 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3331 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3332 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3333 set_tooltip (zoom_in_button, _("Zoom In"));
3334 set_tooltip (zoom_out_button, _("Zoom Out"));
3335 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3336 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3337 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3338 set_tooltip (tav_expand_button, _("Expand Tracks"));
3339 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3340 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3341 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3342 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3343 set_tooltip (edit_point_selector, _("Edit Point"));
3344 set_tooltip (edit_mode_selector, _("Edit Mode"));
3345 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3349 Editor::convert_drop_to_paths (
3350 vector<string>& paths,
3351 const RefPtr<Gdk::DragContext>& /*context*/,
3354 const SelectionData& data,
3358 if (_session == 0) {
3362 vector<string> uris = data.get_uris();
3366 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3367 are actually URI lists. So do it by hand.
3370 if (data.get_target() != "text/plain") {
3374 /* Parse the "uri-list" format that Nautilus provides,
3375 where each pathname is delimited by \r\n.
3377 THERE MAY BE NO NULL TERMINATING CHAR!!!
3380 string txt = data.get_text();
3384 p = (char *) malloc (txt.length() + 1);
3385 txt.copy (p, txt.length(), 0);
3386 p[txt.length()] = '\0';
3392 while (g_ascii_isspace (*p))
3396 while (*q && (*q != '\n') && (*q != '\r')) {
3403 while (q > p && g_ascii_isspace (*q))
3408 uris.push_back (string (p, q - p + 1));
3412 p = strchr (p, '\n');
3424 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3425 if ((*i).substr (0,7) == "file://") {
3426 paths.push_back (Glib::filename_from_uri (*i));
3434 Editor::new_tempo_section ()
3439 Editor::map_transport_state ()
3441 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3443 if (_session && _session->transport_stopped()) {
3444 have_pending_keyboard_selection = false;
3447 update_loop_range_view ();
3453 Editor::begin_selection_op_history ()
3455 selection_op_cmd_depth = 0;
3456 selection_op_history_it = 0;
3458 while(!selection_op_history.empty()) {
3459 delete selection_op_history.front();
3460 selection_op_history.pop_front();
3463 selection_undo_action->set_sensitive (false);
3464 selection_redo_action->set_sensitive (false);
3465 selection_op_history.push_front (&_selection_memento->get_state ());
3469 Editor::begin_reversible_selection_op (string name)
3472 //cerr << name << endl;
3473 /* begin/commit pairs can be nested */
3474 selection_op_cmd_depth++;
3479 Editor::commit_reversible_selection_op ()
3482 if (selection_op_cmd_depth == 1) {
3484 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3486 The user has undone some selection ops and then made a new one,
3487 making anything earlier in the list invalid.
3490 list<XMLNode *>::iterator it = selection_op_history.begin();
3491 list<XMLNode *>::iterator e_it = it;
3492 advance (e_it, selection_op_history_it);
3494 for ( ; it != e_it; ++it) {
3497 selection_op_history.erase (selection_op_history.begin(), e_it);
3500 selection_op_history.push_front (&_selection_memento->get_state ());
3501 selection_op_history_it = 0;
3503 selection_undo_action->set_sensitive (true);
3504 selection_redo_action->set_sensitive (false);
3507 if (selection_op_cmd_depth > 0) {
3508 selection_op_cmd_depth--;
3514 Editor::undo_selection_op ()
3517 selection_op_history_it++;
3519 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3520 if (n == selection_op_history_it) {
3521 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3522 selection_redo_action->set_sensitive (true);
3526 /* is there an earlier entry? */
3527 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3528 selection_undo_action->set_sensitive (false);
3534 Editor::redo_selection_op ()
3537 if (selection_op_history_it > 0) {
3538 selection_op_history_it--;
3541 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3542 if (n == selection_op_history_it) {
3543 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3544 selection_undo_action->set_sensitive (true);
3549 if (selection_op_history_it == 0) {
3550 selection_redo_action->set_sensitive (false);
3556 Editor::begin_reversible_command (string name)
3559 before.push_back (&_selection_memento->get_state ());
3560 _session->begin_reversible_command (name);
3565 Editor::begin_reversible_command (GQuark q)
3568 before.push_back (&_selection_memento->get_state ());
3569 _session->begin_reversible_command (q);
3574 Editor::abort_reversible_command ()
3577 while(!before.empty()) {
3578 delete before.front();
3581 _session->abort_reversible_command ();
3586 Editor::commit_reversible_command ()
3589 if (before.size() == 1) {
3590 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3591 redo_action->set_sensitive(false);
3592 undo_action->set_sensitive(true);
3593 begin_selection_op_history ();
3596 if (before.empty()) {
3597 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3602 _session->commit_reversible_command ();
3607 Editor::history_changed ()
3611 if (undo_action && _session) {
3612 if (_session->undo_depth() == 0) {
3613 label = S_("Command|Undo");
3615 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3617 undo_action->property_label() = label;
3620 if (redo_action && _session) {
3621 if (_session->redo_depth() == 0) {
3623 redo_action->set_sensitive (false);
3625 label = string_compose(_("Redo (%1)"), _session->next_redo());
3626 redo_action->set_sensitive (true);
3628 redo_action->property_label() = label;
3633 Editor::duplicate_range (bool with_dialog)
3637 RegionSelection rs = get_regions_from_selection_and_entered ();
3639 if ( selection->time.length() == 0 && rs.empty()) {
3645 ArdourDialog win (_("Duplicate"));
3646 Label label (_("Number of duplications:"));
3647 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3648 SpinButton spinner (adjustment, 0.0, 1);
3651 win.get_vbox()->set_spacing (12);
3652 win.get_vbox()->pack_start (hbox);
3653 hbox.set_border_width (6);
3654 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3656 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3657 place, visually. so do this by hand.
3660 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3661 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3662 spinner.grab_focus();
3668 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3669 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3670 win.set_default_response (RESPONSE_ACCEPT);
3672 spinner.grab_focus ();
3674 switch (win.run ()) {
3675 case RESPONSE_ACCEPT:
3681 times = adjustment.get_value();
3684 if ((current_mouse_mode() == Editing::MouseRange)) {
3685 if (selection->time.length()) {
3686 duplicate_selection (times);
3688 } else if (get_smart_mode()) {
3689 if (selection->time.length()) {
3690 duplicate_selection (times);
3692 duplicate_some_regions (rs, times);
3694 duplicate_some_regions (rs, times);
3699 Editor::set_edit_mode (EditMode m)
3701 Config->set_edit_mode (m);
3705 Editor::cycle_edit_mode ()
3707 switch (Config->get_edit_mode()) {
3709 Config->set_edit_mode (Ripple);
3713 Config->set_edit_mode (Lock);
3716 Config->set_edit_mode (Slide);
3722 Editor::edit_mode_selection_done ( EditMode m )
3724 Config->set_edit_mode ( m );
3728 Editor::snap_type_selection_done (SnapType snaptype)
3730 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3732 ract->set_active ();
3737 Editor::snap_mode_selection_done (SnapMode mode)
3739 RefPtr<RadioAction> ract = snap_mode_action (mode);
3742 ract->set_active (true);
3747 Editor::cycle_edit_point (bool with_marker)
3749 if(Profile->get_mixbus())
3750 with_marker = false;
3752 switch (_edit_point) {
3754 set_edit_point_preference (EditAtPlayhead);
3756 case EditAtPlayhead:
3758 set_edit_point_preference (EditAtSelectedMarker);
3760 set_edit_point_preference (EditAtMouse);
3763 case EditAtSelectedMarker:
3764 set_edit_point_preference (EditAtMouse);
3770 Editor::edit_point_selection_done (EditPoint ep)
3772 set_edit_point_preference ( ep );
3776 Editor::build_zoom_focus_menu ()
3778 using namespace Menu_Helpers;
3780 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3781 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3782 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3783 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3784 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3785 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3787 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3791 Editor::zoom_focus_selection_done ( ZoomFocus f )
3793 RefPtr<RadioAction> ract = zoom_focus_action (f);
3795 ract->set_active ();
3800 Editor::build_track_count_menu ()
3802 using namespace Menu_Helpers;
3804 if (!Profile->get_mixbus()) {
3805 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3806 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3807 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3808 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3809 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3810 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3811 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3812 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3813 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3814 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3815 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3816 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3817 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3819 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3820 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3821 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3822 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3823 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3824 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3825 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3826 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3827 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3828 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3830 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3831 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3832 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3833 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3834 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3835 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3836 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3837 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3838 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3839 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3840 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3845 Editor::set_zoom_preset (int64_t ms)
3848 temporal_zoom_session();
3852 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3853 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3857 Editor::set_visible_track_count (int32_t n)
3859 _visible_track_count = n;
3861 /* if the canvas hasn't really been allocated any size yet, just
3862 record the desired number of visible tracks and return. when canvas
3863 allocation happens, we will get called again and then we can do the
3867 if (_visible_canvas_height <= 1) {
3873 DisplaySuspender ds;
3875 if (_visible_track_count > 0) {
3876 h = trackviews_height() / _visible_track_count;
3877 std::ostringstream s;
3878 s << _visible_track_count;
3880 } else if (_visible_track_count == 0) {
3882 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3883 if ((*i)->marked_for_display()) {
3887 h = trackviews_height() / n;
3890 /* negative value means that the visible track count has
3891 been overridden by explicit track height changes.
3893 visible_tracks_selector.set_text (X_("*"));
3897 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3898 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3901 if (str != visible_tracks_selector.get_text()) {
3902 visible_tracks_selector.set_text (str);
3907 Editor::override_visible_track_count ()
3909 _visible_track_count = -1;
3910 visible_tracks_selector.set_text ( _("*") );
3914 Editor::edit_controls_button_release (GdkEventButton* ev)
3916 if (Keyboard::is_context_menu_event (ev)) {
3917 ARDOUR_UI::instance()->add_route ();
3918 } else if (ev->button == 1) {
3919 selection->clear_tracks ();
3926 Editor::mouse_select_button_release (GdkEventButton* ev)
3928 /* this handles just right-clicks */
3930 if (ev->button != 3) {
3938 Editor::set_zoom_focus (ZoomFocus f)
3940 string str = zoom_focus_strings[(int)f];
3942 if (str != zoom_focus_selector.get_text()) {
3943 zoom_focus_selector.set_text (str);
3946 if (zoom_focus != f) {
3953 Editor::cycle_zoom_focus ()
3955 switch (zoom_focus) {
3957 set_zoom_focus (ZoomFocusRight);
3959 case ZoomFocusRight:
3960 set_zoom_focus (ZoomFocusCenter);
3962 case ZoomFocusCenter:
3963 set_zoom_focus (ZoomFocusPlayhead);
3965 case ZoomFocusPlayhead:
3966 set_zoom_focus (ZoomFocusMouse);
3968 case ZoomFocusMouse:
3969 set_zoom_focus (ZoomFocusEdit);
3972 set_zoom_focus (ZoomFocusLeft);
3978 Editor::set_show_measures (bool yn)
3980 if (_show_measures != yn) {
3983 if ((_show_measures = yn) == true) {
3985 tempo_lines->show();
3988 std::vector<TempoMap::BBTPoint> grid;
3989 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3990 draw_measures (grid);
3998 Editor::toggle_follow_playhead ()
4000 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
4002 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4003 set_follow_playhead (tact->get_active());
4007 /** @param yn true to follow playhead, otherwise false.
4008 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4011 Editor::set_follow_playhead (bool yn, bool catch_up)
4013 if (_follow_playhead != yn) {
4014 if ((_follow_playhead = yn) == true && catch_up) {
4016 reset_x_origin_to_follow_playhead ();
4023 Editor::toggle_stationary_playhead ()
4025 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4027 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4028 set_stationary_playhead (tact->get_active());
4033 Editor::set_stationary_playhead (bool yn)
4035 if (_stationary_playhead != yn) {
4036 if ((_stationary_playhead = yn) == true) {
4038 // FIXME need a 3.0 equivalent of this 2.X call
4039 // update_current_screen ();
4046 Editor::playlist_selector () const
4048 return *_playlist_selector;
4052 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4054 if (paste_count == 0) {
4055 /* don't bother calculating an offset that will be zero anyway */
4059 /* calculate basic unsnapped multi-paste offset */
4060 framecnt_t offset = paste_count * duration;
4062 /* snap offset so pos + offset is aligned to the grid */
4063 MusicFrame offset_pos (pos + offset, 0);
4064 snap_to(offset_pos, RoundUpMaybe);
4065 offset = offset_pos.frame - pos;
4071 Editor::get_grid_beat_divisions(framepos_t position)
4073 switch (_snap_type) {
4074 case SnapToBeatDiv128: return 128;
4075 case SnapToBeatDiv64: return 64;
4076 case SnapToBeatDiv32: return 32;
4077 case SnapToBeatDiv28: return 28;
4078 case SnapToBeatDiv24: return 24;
4079 case SnapToBeatDiv20: return 20;
4080 case SnapToBeatDiv16: return 16;
4081 case SnapToBeatDiv14: return 14;
4082 case SnapToBeatDiv12: return 12;
4083 case SnapToBeatDiv10: return 10;
4084 case SnapToBeatDiv8: return 8;
4085 case SnapToBeatDiv7: return 7;
4086 case SnapToBeatDiv6: return 6;
4087 case SnapToBeatDiv5: return 5;
4088 case SnapToBeatDiv4: return 4;
4089 case SnapToBeatDiv3: return 3;
4090 case SnapToBeatDiv2: return 2;
4096 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4097 if the grid is non-musical, returns 0.
4098 if the grid is snapped to bars, returns -1.
4099 @param event_state the current keyboard modifier mask.
4102 Editor::get_grid_music_divisions (uint32_t event_state)
4104 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4108 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4112 switch (_snap_type) {
4113 case SnapToBeatDiv128: return 128;
4114 case SnapToBeatDiv64: return 64;
4115 case SnapToBeatDiv32: return 32;
4116 case SnapToBeatDiv28: return 28;
4117 case SnapToBeatDiv24: return 24;
4118 case SnapToBeatDiv20: return 20;
4119 case SnapToBeatDiv16: return 16;
4120 case SnapToBeatDiv14: return 14;
4121 case SnapToBeatDiv12: return 12;
4122 case SnapToBeatDiv10: return 10;
4123 case SnapToBeatDiv8: return 8;
4124 case SnapToBeatDiv7: return 7;
4125 case SnapToBeatDiv6: return 6;
4126 case SnapToBeatDiv5: return 5;
4127 case SnapToBeatDiv4: return 4;
4128 case SnapToBeatDiv3: return 3;
4129 case SnapToBeatDiv2: return 2;
4130 case SnapToBeat: return 1;
4131 case SnapToBar : return -1;
4138 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4142 const unsigned divisions = get_grid_beat_divisions(position);
4144 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4147 switch (_snap_type) {
4149 return Evoral::Beats(4.0 / _session->tempo_map().meter_at_frame (position).note_divisor());
4152 const Meter& m = _session->tempo_map().meter_at_frame (position);
4153 return Evoral::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4161 return Evoral::Beats();
4165 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4169 ret = nudge_clock->current_duration (pos);
4170 next = ret + 1; /* XXXX fix me */
4176 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4178 ArdourDialog dialog (_("Playlist Deletion"));
4179 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4180 "If it is kept, its audio files will not be cleaned.\n"
4181 "If it is deleted, audio files used by it alone will be cleaned."),
4184 dialog.set_position (WIN_POS_CENTER);
4185 dialog.get_vbox()->pack_start (label);
4189 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4190 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4191 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4192 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4193 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4195 // by default gtk uses the left most button
4196 keep->grab_focus ();
4198 switch (dialog.run ()) {
4200 /* keep this and all remaining ones */
4205 /* delete this and all others */
4209 case RESPONSE_ACCEPT:
4210 /* delete the playlist */
4214 case RESPONSE_REJECT:
4215 /* keep the playlist */
4227 Editor::audio_region_selection_covers (framepos_t where)
4229 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4230 if ((*a)->region()->covers (where)) {
4239 Editor::prepare_for_cleanup ()
4241 cut_buffer->clear_regions ();
4242 cut_buffer->clear_playlists ();
4244 selection->clear_regions ();
4245 selection->clear_playlists ();
4247 _regions->suspend_redisplay ();
4251 Editor::finish_cleanup ()
4253 _regions->resume_redisplay ();
4257 Editor::transport_loop_location()
4260 return _session->locations()->auto_loop_location();
4267 Editor::transport_punch_location()
4270 return _session->locations()->auto_punch_location();
4277 Editor::control_layout_scroll (GdkEventScroll* ev)
4279 /* Just forward to the normal canvas scroll method. The coordinate
4280 systems are different but since the canvas is always larger than the
4281 track headers, and aligned with the trackview area, this will work.
4283 In the not too distant future this layout is going away anyway and
4284 headers will be on the canvas.
4286 return canvas_scroll_event (ev, false);
4290 Editor::session_state_saved (string)
4293 _snapshots->redisplay ();
4297 Editor::maximise_editing_space ()
4303 Gtk::Window* toplevel = current_toplevel();
4306 toplevel->fullscreen ();
4312 Editor::restore_editing_space ()
4318 Gtk::Window* toplevel = current_toplevel();
4321 toplevel->unfullscreen();
4327 * Make new playlists for a given track and also any others that belong
4328 * to the same active route group with the `select' property.
4333 Editor::new_playlists (TimeAxisView* v)
4335 begin_reversible_command (_("new playlists"));
4336 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4337 _session->playlists->get (playlists);
4338 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4339 commit_reversible_command ();
4343 * Use a copy of the current playlist for a given track and also any others that belong
4344 * to the same active route group with the `select' property.
4349 Editor::copy_playlists (TimeAxisView* v)
4351 begin_reversible_command (_("copy playlists"));
4352 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4353 _session->playlists->get (playlists);
4354 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4355 commit_reversible_command ();
4358 /** Clear the current playlist for a given track and also any others that belong
4359 * to the same active route group with the `select' property.
4364 Editor::clear_playlists (TimeAxisView* v)
4366 begin_reversible_command (_("clear playlists"));
4367 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4368 _session->playlists->get (playlists);
4369 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4370 commit_reversible_command ();
4374 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4376 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4380 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4382 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4386 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4388 atv.clear_playlist ();
4392 Editor::get_y_origin () const
4394 return vertical_adjustment.get_value ();
4397 /** Queue up a change to the viewport x origin.
4398 * @param frame New x origin.
4401 Editor::reset_x_origin (framepos_t frame)
4403 pending_visual_change.add (VisualChange::TimeOrigin);
4404 pending_visual_change.time_origin = frame;
4405 ensure_visual_change_idle_handler ();
4409 Editor::reset_y_origin (double y)
4411 pending_visual_change.add (VisualChange::YOrigin);
4412 pending_visual_change.y_origin = y;
4413 ensure_visual_change_idle_handler ();
4417 Editor::reset_zoom (framecnt_t spp)
4419 if (spp == samples_per_pixel) {
4423 pending_visual_change.add (VisualChange::ZoomLevel);
4424 pending_visual_change.samples_per_pixel = spp;
4425 ensure_visual_change_idle_handler ();
4429 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4431 reset_x_origin (frame);
4434 if (!no_save_visual) {
4435 undo_visual_stack.push_back (current_visual_state(false));
4439 Editor::VisualState::VisualState (bool with_tracks)
4440 : gui_state (with_tracks ? new GUIObjectState : 0)
4444 Editor::VisualState::~VisualState ()
4449 Editor::VisualState*
4450 Editor::current_visual_state (bool with_tracks)
4452 VisualState* vs = new VisualState (with_tracks);
4453 vs->y_position = vertical_adjustment.get_value();
4454 vs->samples_per_pixel = samples_per_pixel;
4455 vs->leftmost_frame = leftmost_frame;
4456 vs->zoom_focus = zoom_focus;
4459 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4466 Editor::undo_visual_state ()
4468 if (undo_visual_stack.empty()) {
4472 VisualState* vs = undo_visual_stack.back();
4473 undo_visual_stack.pop_back();
4476 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4479 use_visual_state (*vs);
4484 Editor::redo_visual_state ()
4486 if (redo_visual_stack.empty()) {
4490 VisualState* vs = redo_visual_stack.back();
4491 redo_visual_stack.pop_back();
4493 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4494 // why do we check here?
4495 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4498 use_visual_state (*vs);
4503 Editor::swap_visual_state ()
4505 if (undo_visual_stack.empty()) {
4506 redo_visual_state ();
4508 undo_visual_state ();
4513 Editor::use_visual_state (VisualState& vs)
4515 PBD::Unwinder<bool> nsv (no_save_visual, true);
4516 DisplaySuspender ds;
4518 vertical_adjustment.set_value (vs.y_position);
4520 set_zoom_focus (vs.zoom_focus);
4521 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4524 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4526 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4527 (*i)->clear_property_cache();
4528 (*i)->reset_visual_state ();
4532 _routes->update_visibility ();
4535 /** This is the core function that controls the zoom level of the canvas. It is called
4536 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4537 * @param spp new number of samples per pixel
4540 Editor::set_samples_per_pixel (framecnt_t spp)
4546 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4547 const framecnt_t lots_of_pixels = 4000;
4549 /* if the zoom level is greater than what you'd get trying to display 3
4550 * days of audio on a really big screen, then it's too big.
4553 if (spp * lots_of_pixels > three_days) {
4557 samples_per_pixel = spp;
4560 tempo_lines->tempo_map_changed();
4563 bool const showing_time_selection = selection->time.length() > 0;
4565 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4566 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4567 (*i)->reshow_selection (selection->time);
4571 ZoomChanged (); /* EMIT_SIGNAL */
4573 ArdourCanvas::GtkCanvasViewport* c;
4575 c = get_track_canvas();
4577 c->canvas()->zoomed ();
4580 if (playhead_cursor) {
4581 playhead_cursor->set_position (playhead_cursor->current_frame ());
4584 refresh_location_display();
4585 _summary->set_overlays_dirty ();
4587 update_marker_labels ();
4593 Editor::playhead_cursor_sample () const
4595 return playhead_cursor->current_frame();
4599 Editor::queue_visual_videotimeline_update ()
4602 * pending_visual_change.add (VisualChange::VideoTimeline);
4603 * or maybe even more specific: which videotimeline-image
4604 * currently it calls update_video_timeline() to update
4605 * _all outdated_ images on the video-timeline.
4606 * see 'exposeimg()' in video_image_frame.cc
4608 ensure_visual_change_idle_handler ();
4612 Editor::ensure_visual_change_idle_handler ()
4614 if (pending_visual_change.idle_handler_id < 0) {
4615 // see comment in add_to_idle_resize above.
4616 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4617 pending_visual_change.being_handled = false;
4622 Editor::_idle_visual_changer (void* arg)
4624 return static_cast<Editor*>(arg)->idle_visual_changer ();
4628 Editor::idle_visual_changer ()
4630 /* set_horizontal_position() below (and maybe other calls) call
4631 gtk_main_iteration(), so it's possible that a signal will be handled
4632 half-way through this method. If this signal wants an
4633 idle_visual_changer we must schedule another one after this one, so
4634 mark the idle_handler_id as -1 here to allow that. Also make a note
4635 that we are doing the visual change, so that changes in response to
4636 super-rapid-screen-update can be dropped if we are still processing
4640 pending_visual_change.idle_handler_id = -1;
4641 pending_visual_change.being_handled = true;
4643 VisualChange vc = pending_visual_change;
4645 pending_visual_change.pending = (VisualChange::Type) 0;
4647 visual_changer (vc);
4649 pending_visual_change.being_handled = false;
4651 return 0; /* this is always a one-shot call */
4655 Editor::visual_changer (const VisualChange& vc)
4657 double const last_time_origin = horizontal_position ();
4659 if (vc.pending & VisualChange::ZoomLevel) {
4660 set_samples_per_pixel (vc.samples_per_pixel);
4662 compute_fixed_ruler_scale ();
4664 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4665 update_tempo_based_rulers ();
4667 update_video_timeline();
4670 if (vc.pending & VisualChange::TimeOrigin) {
4671 set_horizontal_position (vc.time_origin / samples_per_pixel);
4674 if (vc.pending & VisualChange::YOrigin) {
4675 vertical_adjustment.set_value (vc.y_origin);
4678 if (last_time_origin == horizontal_position ()) {
4679 /* changed signal not emitted */
4680 update_fixed_rulers ();
4681 redisplay_tempo (true);
4684 if (!(vc.pending & VisualChange::ZoomLevel)) {
4685 update_video_timeline();
4688 _summary->set_overlays_dirty ();
4691 struct EditorOrderTimeAxisSorter {
4692 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4693 return a->order () < b->order ();
4698 Editor::sort_track_selection (TrackViewList& sel)
4700 EditorOrderTimeAxisSorter cmp;
4705 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4708 framepos_t where = 0;
4709 EditPoint ep = _edit_point;
4711 if (Profile->get_mixbus()) {
4712 if (ep == EditAtSelectedMarker) {
4713 ep = EditAtPlayhead;
4717 if (from_outside_canvas && (ep == EditAtMouse)) {
4718 ep = EditAtPlayhead;
4719 } else if (from_context_menu && (ep == EditAtMouse)) {
4720 return canvas_event_sample (&context_click_event, 0, 0);
4723 if (entered_marker) {
4724 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4725 return entered_marker->position();
4728 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4729 ep = EditAtSelectedMarker;
4732 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4733 ep = EditAtPlayhead;
4736 MusicFrame snap_mf (0, 0);
4739 case EditAtPlayhead:
4740 if (_dragging_playhead) {
4741 where = *_control_scroll_target;
4743 where = _session->audible_frame();
4745 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4748 case EditAtSelectedMarker:
4749 if (!selection->markers.empty()) {
4751 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4754 where = loc->start();
4758 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4766 if (!mouse_frame (where, ignored)) {
4767 /* XXX not right but what can we do ? */
4770 snap_mf.frame = where;
4772 where = snap_mf.frame;
4773 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4781 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4783 if (!_session) return;
4785 begin_reversible_command (cmd);
4789 if ((tll = transport_loop_location()) == 0) {
4790 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4791 XMLNode &before = _session->locations()->get_state();
4792 _session->locations()->add (loc, true);
4793 _session->set_auto_loop_location (loc);
4794 XMLNode &after = _session->locations()->get_state();
4795 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4797 XMLNode &before = tll->get_state();
4798 tll->set_hidden (false, this);
4799 tll->set (start, end);
4800 XMLNode &after = tll->get_state();
4801 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4804 commit_reversible_command ();
4808 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4810 if (!_session) return;
4812 begin_reversible_command (cmd);
4816 if ((tpl = transport_punch_location()) == 0) {
4817 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4818 XMLNode &before = _session->locations()->get_state();
4819 _session->locations()->add (loc, true);
4820 _session->set_auto_punch_location (loc);
4821 XMLNode &after = _session->locations()->get_state();
4822 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4824 XMLNode &before = tpl->get_state();
4825 tpl->set_hidden (false, this);
4826 tpl->set (start, end);
4827 XMLNode &after = tpl->get_state();
4828 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4831 commit_reversible_command ();
4834 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4835 * @param rs List to which found regions are added.
4836 * @param where Time to look at.
4837 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4840 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4842 const TrackViewList* tracks;
4845 tracks = &track_views;
4850 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4852 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4855 boost::shared_ptr<Track> tr;
4856 boost::shared_ptr<Playlist> pl;
4858 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4860 boost::shared_ptr<RegionList> regions = pl->regions_at (
4861 (framepos_t) floor ( (double) where * tr->speed()));
4863 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4864 RegionView* rv = rtv->view()->find_view (*i);
4875 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4877 const TrackViewList* tracks;
4880 tracks = &track_views;
4885 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4886 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4888 boost::shared_ptr<Track> tr;
4889 boost::shared_ptr<Playlist> pl;
4891 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4893 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4894 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4896 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4898 RegionView* rv = rtv->view()->find_view (*i);
4909 /** Get regions using the following method:
4911 * Make a region list using:
4912 * (a) any selected regions
4913 * (b) the intersection of any selected tracks and the edit point(*)
4914 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4916 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4918 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4922 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4924 RegionSelection regions;
4926 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4927 regions.add (entered_regionview);
4929 regions = selection->regions;
4932 if ( regions.empty() ) {
4933 TrackViewList tracks = selection->tracks;
4935 if (!tracks.empty()) {
4936 /* no region selected or entered, but some selected tracks:
4937 * act on all regions on the selected tracks at the edit point
4939 framepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
4940 get_regions_at(regions, where, tracks);
4947 /** Get regions using the following method:
4949 * Make a region list using:
4950 * (a) any selected regions
4951 * (b) the intersection of any selected tracks and the edit point(*)
4952 * (c) if neither exists, then whatever region is under the mouse
4954 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4956 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4959 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4961 RegionSelection regions;
4963 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4964 regions.add (entered_regionview);
4966 regions = selection->regions;
4969 if ( regions.empty() ) {
4970 TrackViewList tracks = selection->tracks;
4972 if (!tracks.empty()) {
4973 /* no region selected or entered, but some selected tracks:
4974 * act on all regions on the selected tracks at the edit point
4976 get_regions_at(regions, pos, tracks);
4983 /** Start with regions that are selected, or the entered regionview if none are selected.
4984 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4985 * of the regions that we started with.
4989 Editor::get_regions_from_selection_and_entered () const
4991 RegionSelection regions = selection->regions;
4993 if (regions.empty() && entered_regionview) {
4994 regions.add (entered_regionview);
5001 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
5003 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5004 RouteTimeAxisView* rtav;
5006 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5007 boost::shared_ptr<Playlist> pl;
5008 std::vector<boost::shared_ptr<Region> > results;
5009 boost::shared_ptr<Track> tr;
5011 if ((tr = rtav->track()) == 0) {
5016 if ((pl = (tr->playlist())) != 0) {
5017 boost::shared_ptr<Region> r = pl->region_by_id (id);
5019 RegionView* rv = rtav->view()->find_view (r);
5021 regions.push_back (rv);
5030 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5033 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5034 MidiTimeAxisView* mtav;
5036 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5038 mtav->get_per_region_note_selection (selection);
5045 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5047 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5049 RouteTimeAxisView* tatv;
5051 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5053 boost::shared_ptr<Playlist> pl;
5054 vector<boost::shared_ptr<Region> > results;
5056 boost::shared_ptr<Track> tr;
5058 if ((tr = tatv->track()) == 0) {
5063 if ((pl = (tr->playlist())) != 0) {
5064 if (src_comparison) {
5065 pl->get_source_equivalent_regions (region, results);
5067 pl->get_region_list_equivalent_regions (region, results);
5071 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5072 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5073 regions.push_back (marv);
5082 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
5084 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5085 RouteTimeAxisView* tatv;
5086 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5087 if (!tatv->track()) {
5090 RegionView* marv = tatv->view()->find_view (region);
5100 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5102 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5103 RouteTimeAxisView* rtav;
5104 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5105 if (rtav->route() == route) {
5114 Editor::show_rhythm_ferret ()
5116 if (rhythm_ferret == 0) {
5117 rhythm_ferret = new RhythmFerret(*this);
5120 rhythm_ferret->set_session (_session);
5121 rhythm_ferret->show ();
5122 rhythm_ferret->present ();
5126 Editor::first_idle ()
5128 MessageDialog* dialog = 0;
5130 if (track_views.size() > 1) {
5131 Timers::TimerSuspender t;
5132 dialog = new MessageDialog (
5133 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5137 ARDOUR_UI::instance()->flush_pending (60);
5140 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5144 // first idle adds route children (automation tracks), so we need to redisplay here
5145 _routes->redisplay ();
5149 if (_session->undo_depth() == 0) {
5150 undo_action->set_sensitive(false);
5152 redo_action->set_sensitive(false);
5153 begin_selection_op_history ();
5159 Editor::_idle_resize (gpointer arg)
5161 return ((Editor*)arg)->idle_resize ();
5165 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5167 if (resize_idle_id < 0) {
5168 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5169 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5170 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5172 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5173 _pending_resize_amount = 0;
5176 /* make a note of the smallest resulting height, so that we can clamp the
5177 lower limit at TimeAxisView::hSmall */
5179 int32_t min_resulting = INT32_MAX;
5181 _pending_resize_amount += h;
5182 _pending_resize_view = view;
5184 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5186 if (selection->tracks.contains (_pending_resize_view)) {
5187 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5188 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5192 if (min_resulting < 0) {
5197 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5198 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5202 /** Handle pending resizing of tracks */
5204 Editor::idle_resize ()
5206 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5208 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5209 selection->tracks.contains (_pending_resize_view)) {
5211 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5212 if (*i != _pending_resize_view) {
5213 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5218 _pending_resize_amount = 0;
5219 _group_tabs->set_dirty ();
5220 resize_idle_id = -1;
5228 ENSURE_GUI_THREAD (*this, &Editor::located);
5231 playhead_cursor->set_position (_session->audible_frame ());
5232 if (_follow_playhead && !_pending_initial_locate) {
5233 reset_x_origin_to_follow_playhead ();
5237 _pending_locate_request = false;
5238 _pending_initial_locate = false;
5242 Editor::region_view_added (RegionView * rv)
5244 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5245 if (rv->region ()->id () == (*pr)) {
5246 selection->add (rv);
5247 selection->regions.pending.erase (pr);
5252 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5254 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5255 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5256 if (rv->region()->id () == (*rnote).first) {
5257 mrv->select_notes ((*rnote).second);
5258 selection->pending_midi_note_selection.erase(rnote);
5264 _summary->set_background_dirty ();
5268 Editor::region_view_removed ()
5270 _summary->set_background_dirty ();
5274 Editor::axis_view_from_stripable (boost::shared_ptr<Stripable> s) const
5276 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5277 if ((*j)->stripable() == s) {
5287 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5291 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5292 TimeAxisView* tv = axis_view_from_stripable (*i);
5302 Editor::suspend_route_redisplay ()
5305 _routes->suspend_redisplay();
5310 Editor::resume_route_redisplay ()
5313 _routes->redisplay(); // queue redisplay
5314 _routes->resume_redisplay();
5319 Editor::add_vcas (VCAList& vlist)
5323 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5324 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5327 add_stripables (sl);
5331 Editor::add_routes (RouteList& rlist)
5335 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5339 add_stripables (sl);
5343 Editor::add_stripables (StripableList& sl)
5345 list<TimeAxisView*> new_views;
5346 boost::shared_ptr<VCA> v;
5347 boost::shared_ptr<Route> r;
5348 TrackViewList new_selection;
5349 bool from_scratch = (track_views.size() == 0);
5351 sl.sort (StripablePresentationInfoSorter());
5353 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5355 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5357 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5359 new_views.push_back (vtv);
5361 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5363 if (r->is_auditioner() || r->is_monitor()) {
5367 RouteTimeAxisView* rtv;
5368 DataType dt = r->input()->default_type();
5370 if (dt == ARDOUR::DataType::AUDIO) {
5371 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5373 } else if (dt == ARDOUR::DataType::MIDI) {
5374 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5377 throw unknown_type();
5380 new_views.push_back (rtv);
5381 track_views.push_back (rtv);
5382 new_selection.push_back (rtv);
5384 rtv->effective_gain_display ();
5386 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5387 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5391 if (new_views.size() > 0) {
5392 _routes->time_axis_views_added (new_views);
5393 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5396 /* note: !new_selection.empty() means that we got some routes rather
5400 if (!from_scratch && !new_selection.empty()) {
5401 selection->tracks.clear();
5402 selection->add (new_selection);
5403 begin_selection_op_history();
5406 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5407 show_editor_mixer (true);
5410 editor_list_button.set_sensitive (true);
5414 Editor::timeaxisview_deleted (TimeAxisView *tv)
5416 if (tv == entered_track) {
5420 if (_session && _session->deletion_in_progress()) {
5421 /* the situation is under control */
5425 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5427 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5429 _routes->route_removed (tv);
5431 TimeAxisView::Children c = tv->get_child_list ();
5432 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5433 if (entered_track == i->get()) {
5438 /* remove it from the list of track views */
5440 TrackViewList::iterator i;
5442 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5443 i = track_views.erase (i);
5446 /* update whatever the current mixer strip is displaying, if revelant */
5448 boost::shared_ptr<Route> route;
5451 route = rtav->route ();
5454 if (current_mixer_strip && current_mixer_strip->route() == route) {
5456 TimeAxisView* next_tv;
5458 if (track_views.empty()) {
5460 } else if (i == track_views.end()) {
5461 next_tv = track_views.front();
5466 // skip VCAs (cannot be selected, n/a in editor-mixer)
5467 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5468 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5469 next_tv = track_views.front();
5471 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5472 /* just in case: no master, only a VCA remains */
5478 set_selected_mixer_strip (*next_tv);
5480 /* make the editor mixer strip go away setting the
5481 * button to inactive (which also unticks the menu option)
5484 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5490 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5495 if (apply_to_selection) {
5496 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5498 TrackSelection::iterator j = i;
5501 hide_track_in_display (*i, false);
5506 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5508 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5509 // this will hide the mixer strip
5510 set_selected_mixer_strip (*tv);
5513 _routes->hide_track_in_display (*tv);
5518 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5523 _routes->show_track_in_display (*tv);
5524 if (move_into_view) {
5525 ensure_time_axis_view_is_visible (*tv, false);
5530 Editor::sync_track_view_list_and_routes ()
5532 track_views = TrackViewList (_routes->views ());
5534 _summary->set_background_dirty();
5535 _group_tabs->set_dirty ();
5537 return false; // do not call again (until needed)
5541 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5543 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5548 /** Find a RouteTimeAxisView by the ID of its route */
5550 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5552 RouteTimeAxisView* v;
5554 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5555 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5556 if(v->route()->id() == id) {
5566 Editor::fit_route_group (RouteGroup *g)
5568 TrackViewList ts = axis_views_from_routes (g->route_list ());
5573 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5575 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5578 _session->cancel_audition ();
5582 if (_session->is_auditioning()) {
5583 _session->cancel_audition ();
5584 if (r == last_audition_region) {
5589 _session->audition_region (r);
5590 last_audition_region = r;
5595 Editor::hide_a_region (boost::shared_ptr<Region> r)
5597 r->set_hidden (true);
5601 Editor::show_a_region (boost::shared_ptr<Region> r)
5603 r->set_hidden (false);
5607 Editor::audition_region_from_region_list ()
5609 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5613 Editor::hide_region_from_region_list ()
5615 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5619 Editor::show_region_in_region_list ()
5621 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5625 Editor::step_edit_status_change (bool yn)
5628 start_step_editing ();
5630 stop_step_editing ();
5635 Editor::start_step_editing ()
5637 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5641 Editor::stop_step_editing ()
5643 step_edit_connection.disconnect ();
5647 Editor::check_step_edit ()
5649 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5650 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5652 mtv->check_step_edit ();
5656 return true; // do it again, till we stop
5660 Editor::scroll_press (Direction dir)
5662 ++_scroll_callbacks;
5664 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5665 /* delay the first auto-repeat */
5671 scroll_backward (1);
5679 scroll_up_one_track ();
5683 scroll_down_one_track ();
5687 /* do hacky auto-repeat */
5688 if (!_scroll_connection.connected ()) {
5690 _scroll_connection = Glib::signal_timeout().connect (
5691 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5694 _scroll_callbacks = 0;
5701 Editor::scroll_release ()
5703 _scroll_connection.disconnect ();
5706 /** Queue a change for the Editor viewport x origin to follow the playhead */
5708 Editor::reset_x_origin_to_follow_playhead ()
5710 framepos_t const frame = playhead_cursor->current_frame ();
5712 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5714 if (_session->transport_speed() < 0) {
5716 if (frame > (current_page_samples() / 2)) {
5717 center_screen (frame-(current_page_samples()/2));
5719 center_screen (current_page_samples()/2);
5726 if (frame < leftmost_frame) {
5728 if (_session->transport_rolling()) {
5729 /* rolling; end up with the playhead at the right of the page */
5730 l = frame - current_page_samples ();
5732 /* not rolling: end up with the playhead 1/4 of the way along the page */
5733 l = frame - current_page_samples() / 4;
5737 if (_session->transport_rolling()) {
5738 /* rolling: end up with the playhead on the left of the page */
5741 /* not rolling: end up with the playhead 3/4 of the way along the page */
5742 l = frame - 3 * current_page_samples() / 4;
5750 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5756 Editor::super_rapid_screen_update ()
5758 if (!_session || !_session->engine().running()) {
5762 /* METERING / MIXER STRIPS */
5764 /* update track meters, if required */
5765 if (contents().is_mapped() && meters_running) {
5766 RouteTimeAxisView* rtv;
5767 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5768 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5769 rtv->fast_update ();
5774 /* and any current mixer strip */
5775 if (current_mixer_strip) {
5776 current_mixer_strip->fast_update ();
5779 /* PLAYHEAD AND VIEWPORT */
5781 framepos_t const frame = _session->audible_frame();
5783 /* There are a few reasons why we might not update the playhead / viewport stuff:
5785 * 1. we don't update things when there's a pending locate request, otherwise
5786 * when the editor requests a locate there is a chance that this method
5787 * will move the playhead before the locate request is processed, causing
5789 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5790 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5793 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5795 last_update_frame = frame;
5797 if (!_dragging_playhead) {
5798 playhead_cursor->set_position (frame);
5801 if (!_stationary_playhead) {
5803 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5804 /* We only do this if we aren't already
5805 handling a visual change (ie if
5806 pending_visual_change.being_handled is
5807 false) so that these requests don't stack
5808 up there are too many of them to handle in
5811 reset_x_origin_to_follow_playhead ();
5816 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5817 framepos_t const frame = playhead_cursor->current_frame ();
5818 double target = ((double)frame - (double)current_page_samples()/2.0);
5819 if (target <= 0.0) {
5822 // compare to EditorCursor::set_position()
5823 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5824 double const new_pos = sample_to_pixel_unrounded (target);
5825 if (rint (new_pos) != rint (old_pos)) {
5826 reset_x_origin (pixel_to_sample (floor (new_pos)));
5837 Editor::session_going_away ()
5839 _have_idled = false;
5841 _session_connections.drop_connections ();
5843 super_rapid_screen_update_connection.disconnect ();
5845 selection->clear ();
5846 cut_buffer->clear ();
5848 clicked_regionview = 0;
5849 clicked_axisview = 0;
5850 clicked_routeview = 0;
5851 entered_regionview = 0;
5853 last_update_frame = 0;
5856 playhead_cursor->hide ();
5858 /* rip everything out of the list displays */
5862 _route_groups->clear ();
5864 /* do this first so that deleting a track doesn't reset cms to null
5865 and thus cause a leak.
5868 if (current_mixer_strip) {
5869 if (current_mixer_strip->get_parent() != 0) {
5870 global_hpacker.remove (*current_mixer_strip);
5872 delete current_mixer_strip;
5873 current_mixer_strip = 0;
5876 /* delete all trackviews */
5878 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5881 track_views.clear ();
5883 nudge_clock->set_session (0);
5885 editor_list_button.set_active(false);
5886 editor_list_button.set_sensitive(false);
5888 /* clear tempo/meter rulers */
5889 remove_metric_marks ();
5891 clear_marker_display ();
5893 stop_step_editing ();
5897 /* get rid of any existing editor mixer strip */
5899 WindowTitle title(Glib::get_application_name());
5900 title += _("Editor");
5902 own_window()->set_title (title.get_string());
5905 SessionHandlePtr::session_going_away ();
5909 Editor::trigger_script (int i)
5911 LuaInstance::instance()-> call_action (i);
5915 Editor::show_editor_list (bool yn)
5918 _editor_list_vbox.show ();
5920 _editor_list_vbox.hide ();
5925 Editor::change_region_layering_order (bool from_context_menu)
5927 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5929 if (!clicked_routeview) {
5930 if (layering_order_editor) {
5931 layering_order_editor->hide ();
5936 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5942 boost::shared_ptr<Playlist> pl = track->playlist();
5948 if (layering_order_editor == 0) {
5949 layering_order_editor = new RegionLayeringOrderEditor (*this);
5952 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5953 layering_order_editor->maybe_present ();
5957 Editor::update_region_layering_order_editor ()
5959 if (layering_order_editor && layering_order_editor->is_visible ()) {
5960 change_region_layering_order (true);
5965 Editor::setup_fade_images ()
5967 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5968 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5969 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5970 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5971 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5973 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5974 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5975 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5976 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5977 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5981 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5983 Editor::action_menu_item (std::string const & name)
5985 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5988 return *manage (a->create_menu_item ());
5992 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5994 EventBox* b = manage (new EventBox);
5995 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5996 Label* l = manage (new Label (name));
6000 _the_notebook.append_page (widget, *b);
6004 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6006 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6007 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6010 if (ev->type == GDK_2BUTTON_PRESS) {
6012 /* double-click on a notebook tab shrinks or expands the notebook */
6014 if (_notebook_shrunk) {
6015 if (pre_notebook_shrink_pane_width) {
6016 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6018 _notebook_shrunk = false;
6020 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6022 /* this expands the LHS of the edit pane to cover the notebook
6023 PAGE but leaves the tabs visible.
6025 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6026 _notebook_shrunk = true;
6034 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6036 using namespace Menu_Helpers;
6038 MenuList& items = _control_point_context_menu.items ();
6041 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6042 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6043 if (!can_remove_control_point (item)) {
6044 items.back().set_sensitive (false);
6047 _control_point_context_menu.popup (event->button.button, event->button.time);
6051 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6053 using namespace Menu_Helpers;
6055 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6060 /* We need to get the selection here and pass it to the operations, since
6061 popping up the menu will cause a region leave event which clears
6062 entered_regionview. */
6064 MidiRegionView& mrv = note->region_view();
6065 const RegionSelection rs = get_regions_from_selection_and_entered ();
6066 const uint32_t sel_size = mrv.selection_size ();
6068 MenuList& items = _note_context_menu.items();
6072 items.push_back(MenuElem(_("Delete"),
6073 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6076 items.push_back(MenuElem(_("Edit..."),
6077 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6078 if (sel_size != 1) {
6079 items.back().set_sensitive (false);
6082 items.push_back(MenuElem(_("Transpose..."),
6083 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6086 items.push_back(MenuElem(_("Legatize"),
6087 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6089 items.back().set_sensitive (false);
6092 items.push_back(MenuElem(_("Quantize..."),
6093 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6095 items.push_back(MenuElem(_("Remove Overlap"),
6096 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6098 items.back().set_sensitive (false);
6101 items.push_back(MenuElem(_("Transform..."),
6102 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6104 _note_context_menu.popup (event->button.button, event->button.time);
6108 Editor::zoom_vertical_modifier_released()
6110 _stepping_axis_view = 0;
6114 Editor::ui_parameter_changed (string parameter)
6116 if (parameter == "icon-set") {
6117 while (!_cursor_stack.empty()) {
6118 _cursor_stack.pop_back();
6120 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6121 _cursor_stack.push_back(_cursors->grabber);
6122 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6123 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6125 } else if (parameter == "draggable-playhead") {
6126 if (_verbose_cursor) {
6127 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6133 Editor::use_own_window (bool and_fill_it)
6135 bool new_window = !own_window();
6137 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6139 if (win && new_window) {
6140 win->set_name ("EditorWindow");
6142 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6144 // win->signal_realize().connect (*this, &Editor::on_realize);
6145 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6146 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6147 win->set_data ("ardour-bindings", bindings);
6152 DisplaySuspender ds;
6153 contents().show_all ();
6155 /* XXX: this is a bit unfortunate; it would probably
6156 be nicer if we could just call show () above rather
6157 than needing the show_all ()
6160 /* re-hide stuff if necessary */
6161 editor_list_button_toggled ();
6162 parameter_changed ("show-summary");
6163 parameter_changed ("show-group-tabs");
6164 parameter_changed ("show-zoom-tools");
6166 /* now reset all audio_time_axis heights, because widgets might need
6172 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6173 tv = (static_cast<TimeAxisView*>(*i));
6174 tv->reset_height ();
6177 if (current_mixer_strip) {
6178 current_mixer_strip->hide_things ();
6179 current_mixer_strip->parameter_changed ("mixer-element-visibility");