2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include <gtkmm2ext/keyboard.h>
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
68 #include "ardour/audio_track.h"
69 #include "ardour/audioengine.h"
70 #include "ardour/audioregion.h"
71 #include "ardour/lmath.h"
72 #include "ardour/location.h"
73 #include "ardour/profile.h"
74 #include "ardour/route_group.h"
75 #include "ardour/session_playlists.h"
76 #include "ardour/tempo.h"
77 #include "ardour/utils.h"
79 #include "canvas/debug.h"
80 #include "canvas/text.h"
82 #include "control_protocol/control_protocol.h"
85 #include "analysis_window.h"
86 #include "audio_clock.h"
87 #include "audio_region_view.h"
88 #include "audio_streamview.h"
89 #include "audio_time_axis.h"
90 #include "automation_time_axis.h"
91 #include "bundle_manager.h"
92 #include "crossfade_edit.h"
96 #include "editor_cursors.h"
97 #include "editor_drag.h"
98 #include "editor_group_tabs.h"
99 #include "editor_locations.h"
100 #include "editor_regions.h"
101 #include "editor_route_groups.h"
102 #include "editor_routes.h"
103 #include "editor_snapshots.h"
104 #include "editor_summary.h"
105 #include "global_port_matrix.h"
106 #include "gui_object.h"
107 #include "gui_thread.h"
108 #include "keyboard.h"
110 #include "midi_region_view.h"
111 #include "midi_time_axis.h"
112 #include "mixer_strip.h"
113 #include "mixer_ui.h"
114 #include "mouse_cursors.h"
115 #include "note_base.h"
116 #include "playlist_selector.h"
117 #include "public_editor.h"
118 #include "quantize_dialog.h"
119 #include "region_layering_order_editor.h"
120 #include "rgb_macros.h"
121 #include "rhythm_ferret.h"
122 #include "selection.h"
124 #include "tempo_lines.h"
125 #include "time_axis_view.h"
127 #include "tooltips.h"
128 #include "ui_config.h"
130 #include "verbose_cursor.h"
135 using namespace ARDOUR;
136 using namespace ARDOUR_UI_UTILS;
139 using namespace Glib;
140 using namespace Gtkmm2ext;
141 using namespace Editing;
143 using PBD::internationalize;
145 using Gtkmm2ext::Keyboard;
147 double Editor::timebar_height = 15.0;
149 static const gchar *_snap_type_strings[] = {
183 static const gchar *_snap_mode_strings[] = {
190 static const gchar *_edit_point_strings[] = {
197 static const gchar *_edit_mode_strings[] = {
205 static const gchar *_zoom_focus_strings[] = {
215 #ifdef USE_RUBBERBAND
216 static const gchar *_rb_opt_strings[] = {
219 N_("Balanced multitimbral mixture"),
220 N_("Unpitched percussion with stable notes"),
221 N_("Crisp monophonic instrumental"),
222 N_("Unpitched solo percussion"),
223 N_("Resample without preserving pitch"),
228 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
231 pane_size_watcher (Paned* pane)
233 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
237 Quartz: impossible to access
239 so stop that by preventing it from ever getting too narrow. 35
240 pixels is basically a rough guess at the tab width.
245 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
247 gint pos = pane->get_position ();
249 if (pos > max_width_of_lhs) {
250 pane->set_position (max_width_of_lhs);
255 : PublicEditor (global_hpacker)
256 , editor_mixer_strip_width (Wide)
257 , constructed (false)
258 , _playlist_selector (0)
259 , no_save_visual (false)
261 , samples_per_pixel (2048)
262 , zoom_focus (ZoomFocusPlayhead)
263 , mouse_mode (MouseObject)
264 , pre_internal_snap_type (SnapToBeat)
265 , pre_internal_snap_mode (SnapOff)
266 , internal_snap_type (SnapToBeat)
267 , internal_snap_mode (SnapOff)
268 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
269 , _notebook_shrunk (false)
270 , location_marker_color (0)
271 , location_range_color (0)
272 , location_loop_color (0)
273 , location_punch_color (0)
274 , location_cd_marker_color (0)
276 , _show_marker_lines (false)
277 , clicked_axisview (0)
278 , clicked_routeview (0)
279 , clicked_regionview (0)
280 , clicked_selection (0)
281 , clicked_control_point (0)
282 , button_release_can_deselect (true)
283 , _mouse_changed_selection (false)
284 , region_edit_menu_split_item (0)
285 , region_edit_menu_split_multichannel_item (0)
286 , track_region_edit_playlist_menu (0)
287 , track_edit_playlist_submenu (0)
288 , track_selection_edit_playlist_submenu (0)
289 , _popup_region_menu_item (0)
291 , _track_canvas_viewport (0)
292 , within_track_canvas (false)
293 , _verbose_cursor (0)
297 , range_marker_group (0)
298 , transport_marker_group (0)
299 , cd_marker_group (0)
300 , _time_markers_group (0)
301 , hv_scroll_group (0)
303 , cursor_scroll_group (0)
304 , no_scroll_group (0)
305 , _trackview_group (0)
306 , _drag_motion_group (0)
307 , _canvas_drop_zone (0)
308 , no_ruler_shown_update (false)
309 , ruler_grabbed_widget (0)
311 , minsec_mark_interval (0)
312 , minsec_mark_modulo (0)
314 , timecode_mark_modulo (0)
315 , timecode_nmarks (0)
316 , _samples_ruler_interval (0)
319 , bbt_bar_helper_on (0)
320 , bbt_accent_modulo (0)
325 , visible_timebars (0)
326 , editor_ruler_menu (0)
330 , range_marker_bar (0)
331 , transport_marker_bar (0)
333 , minsec_label (_("Mins:Secs"))
334 , bbt_label (_("Bars:Beats"))
335 , timecode_label (_("Timecode"))
336 , samples_label (_("Samples"))
337 , tempo_label (_("Tempo"))
338 , meter_label (_("Meter"))
339 , mark_label (_("Location Markers"))
340 , range_mark_label (_("Range Markers"))
341 , transport_mark_label (_("Loop/Punch Ranges"))
342 , cd_mark_label (_("CD Markers"))
343 , videotl_label (_("Video Timeline"))
345 , playhead_cursor (0)
346 , edit_packer (4, 4, true)
347 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
348 , horizontal_adjustment (0.0, 0.0, 1e16)
349 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
350 , controls_layout (unused_adjustment, vertical_adjustment)
351 , _scroll_callbacks (0)
352 , _visible_canvas_width (0)
353 , _visible_canvas_height (0)
354 , _full_canvas_height (0)
355 , edit_controls_left_menu (0)
356 , edit_controls_right_menu (0)
357 , last_update_frame (0)
358 , cut_buffer_start (0)
359 , cut_buffer_length (0)
360 , button_bindings (0)
364 , current_interthread_info (0)
365 , analysis_window (0)
366 , select_new_marker (false)
368 , scrubbing_direction (0)
369 , scrub_reversals (0)
370 , scrub_reverse_distance (0)
371 , have_pending_keyboard_selection (false)
372 , pending_keyboard_selection_start (0)
373 , _snap_type (SnapToBeat)
374 , _snap_mode (SnapOff)
375 , snap_threshold (5.0)
376 , ignore_gui_changes (false)
377 , _drags (new DragManager (this))
379 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
380 , _dragging_playhead (false)
381 , _dragging_edit_point (false)
382 , _show_measures (true)
383 , _follow_playhead (true)
384 , _stationary_playhead (false)
387 , global_rect_group (0)
388 , time_line_group (0)
389 , tempo_or_meter_marker_menu (0)
391 , range_marker_menu (0)
392 , transport_marker_menu (0)
393 , new_transport_marker_menu (0)
395 , marker_menu_item (0)
396 , bbt_beat_subdivision (4)
397 , _visible_track_count (-1)
398 , toolbar_selection_clock_table (2,3)
399 , automation_mode_button (_("mode"))
400 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
401 , selection (new Selection (this))
402 , cut_buffer (new Selection (this))
403 , _selection_memento (new SelectionMemento())
404 , _all_region_actions_sensitized (false)
405 , _ignore_region_action (false)
406 , _last_region_menu_was_main (false)
407 , _ignore_follow_edits (false)
408 , cd_marker_bar_drag_rect (0)
409 , range_bar_drag_rect (0)
410 , transport_bar_drag_rect (0)
411 , transport_bar_range_rect (0)
412 , transport_bar_preroll_rect (0)
413 , transport_bar_postroll_rect (0)
414 , transport_loop_range_rect (0)
415 , transport_punch_range_rect (0)
416 , transport_punchin_line (0)
417 , transport_punchout_line (0)
418 , transport_preroll_rect (0)
419 , transport_postroll_rect (0)
421 , rubberband_rect (0)
427 , autoscroll_horizontal_allowed (false)
428 , autoscroll_vertical_allowed (false)
430 , autoscroll_widget (0)
431 , show_gain_after_trim (false)
432 , selection_op_cmd_depth (0)
433 , selection_op_history_it (0)
435 , current_mixer_strip (0)
436 , show_editor_mixer_when_tracks_arrive (false)
437 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
438 , current_stepping_trackview (0)
439 , last_track_height_step_timestamp (0)
441 , entered_regionview (0)
442 , clear_entered_track (false)
443 , _edit_point (EditAtMouse)
444 , meters_running (false)
446 , _have_idled (false)
447 , resize_idle_id (-1)
448 , _pending_resize_amount (0)
449 , _pending_resize_view (0)
450 , _pending_locate_request (false)
451 , _pending_initial_locate (false)
455 , layering_order_editor (0)
456 , _last_cut_copy_source_track (0)
457 , _region_selection_change_updates_region_list (true)
459 , _following_mixer_selection (false)
460 , _control_point_toggled_on_press (false)
461 , _stepping_axis_view (0)
462 , quantize_dialog (0)
463 , _main_menu_disabler (0)
464 , myactions (X_("editor"))
466 /* we are a singleton */
468 PublicEditor::_instance = this;
472 last_event_time.tv_sec = 0;
473 last_event_time.tv_usec = 0;
475 selection_op_history.clear();
478 snap_type_strings = I18N (_snap_type_strings);
479 snap_mode_strings = I18N (_snap_mode_strings);
480 zoom_focus_strings = I18N (_zoom_focus_strings);
481 edit_mode_strings = I18N (_edit_mode_strings);
482 edit_point_strings = I18N (_edit_point_strings);
483 #ifdef USE_RUBBERBAND
484 rb_opt_strings = I18N (_rb_opt_strings);
488 build_edit_mode_menu();
489 build_zoom_focus_menu();
490 build_track_count_menu();
491 build_snap_mode_menu();
492 build_snap_type_menu();
493 build_edit_point_menu();
495 location_marker_color = UIConfiguration::instance().color ("location marker");
496 location_range_color = UIConfiguration::instance().color ("location range");
497 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
498 location_loop_color = UIConfiguration::instance().color ("location loop");
499 location_punch_color = UIConfiguration::instance().color ("location punch");
501 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
503 TimeAxisView::setup_sizes ();
504 ArdourMarker::setup_sizes (timebar_height);
506 bbt_label.set_name ("EditorRulerLabel");
507 bbt_label.set_size_request (-1, (int)timebar_height);
508 bbt_label.set_alignment (1.0, 0.5);
509 bbt_label.set_padding (5,0);
511 bbt_label.set_no_show_all();
512 minsec_label.set_name ("EditorRulerLabel");
513 minsec_label.set_size_request (-1, (int)timebar_height);
514 minsec_label.set_alignment (1.0, 0.5);
515 minsec_label.set_padding (5,0);
516 minsec_label.hide ();
517 minsec_label.set_no_show_all();
518 timecode_label.set_name ("EditorRulerLabel");
519 timecode_label.set_size_request (-1, (int)timebar_height);
520 timecode_label.set_alignment (1.0, 0.5);
521 timecode_label.set_padding (5,0);
522 timecode_label.hide ();
523 timecode_label.set_no_show_all();
524 samples_label.set_name ("EditorRulerLabel");
525 samples_label.set_size_request (-1, (int)timebar_height);
526 samples_label.set_alignment (1.0, 0.5);
527 samples_label.set_padding (5,0);
528 samples_label.hide ();
529 samples_label.set_no_show_all();
531 tempo_label.set_name ("EditorRulerLabel");
532 tempo_label.set_size_request (-1, (int)timebar_height);
533 tempo_label.set_alignment (1.0, 0.5);
534 tempo_label.set_padding (5,0);
536 tempo_label.set_no_show_all();
538 meter_label.set_name ("EditorRulerLabel");
539 meter_label.set_size_request (-1, (int)timebar_height);
540 meter_label.set_alignment (1.0, 0.5);
541 meter_label.set_padding (5,0);
543 meter_label.set_no_show_all();
545 if (Profile->get_trx()) {
546 mark_label.set_text (_("Markers"));
548 mark_label.set_name ("EditorRulerLabel");
549 mark_label.set_size_request (-1, (int)timebar_height);
550 mark_label.set_alignment (1.0, 0.5);
551 mark_label.set_padding (5,0);
553 mark_label.set_no_show_all();
555 cd_mark_label.set_name ("EditorRulerLabel");
556 cd_mark_label.set_size_request (-1, (int)timebar_height);
557 cd_mark_label.set_alignment (1.0, 0.5);
558 cd_mark_label.set_padding (5,0);
559 cd_mark_label.hide();
560 cd_mark_label.set_no_show_all();
562 videotl_bar_height = 4;
563 videotl_label.set_name ("EditorRulerLabel");
564 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
565 videotl_label.set_alignment (1.0, 0.5);
566 videotl_label.set_padding (5,0);
567 videotl_label.hide();
568 videotl_label.set_no_show_all();
570 range_mark_label.set_name ("EditorRulerLabel");
571 range_mark_label.set_size_request (-1, (int)timebar_height);
572 range_mark_label.set_alignment (1.0, 0.5);
573 range_mark_label.set_padding (5,0);
574 range_mark_label.hide();
575 range_mark_label.set_no_show_all();
577 transport_mark_label.set_name ("EditorRulerLabel");
578 transport_mark_label.set_size_request (-1, (int)timebar_height);
579 transport_mark_label.set_alignment (1.0, 0.5);
580 transport_mark_label.set_padding (5,0);
581 transport_mark_label.hide();
582 transport_mark_label.set_no_show_all();
584 initialize_canvas ();
586 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
588 _summary = new EditorSummary (this);
590 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
591 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
593 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
595 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
596 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
598 edit_controls_vbox.set_spacing (0);
599 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
600 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
602 HBox* h = manage (new HBox);
603 _group_tabs = new EditorGroupTabs (this);
604 if (!ARDOUR::Profile->get_trx()) {
605 h->pack_start (*_group_tabs, PACK_SHRINK);
607 h->pack_start (edit_controls_vbox);
608 controls_layout.add (*h);
610 controls_layout.set_name ("EditControlsBase");
611 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
612 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
613 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
615 _cursors = new MouseCursors;
616 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
617 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
619 /* Push default cursor to ever-present bottom of cursor stack. */
620 push_canvas_cursor(_cursors->grabber);
622 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
624 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
625 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
626 pad_line_1->set_outline_color (0xFF0000FF);
632 edit_packer.set_col_spacings (0);
633 edit_packer.set_row_spacings (0);
634 edit_packer.set_homogeneous (false);
635 edit_packer.set_border_width (0);
636 edit_packer.set_name ("EditorWindow");
638 time_bars_event_box.add (time_bars_vbox);
639 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
640 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
642 /* labels for the time bars */
643 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
645 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
647 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
649 bottom_hbox.set_border_width (2);
650 bottom_hbox.set_spacing (3);
652 _route_groups = new EditorRouteGroups (this);
653 _routes = new EditorRoutes (this);
654 _regions = new EditorRegions (this);
655 _snapshots = new EditorSnapshots (this);
656 _locations = new EditorLocations (this);
658 /* these are static location signals */
660 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
661 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
662 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
664 add_notebook_page (_("Regions"), _regions->widget ());
665 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
666 add_notebook_page (_("Snapshots"), _snapshots->widget ());
667 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
668 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
670 _the_notebook.set_show_tabs (true);
671 _the_notebook.set_scrollable (true);
672 _the_notebook.popup_disable ();
673 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
674 _the_notebook.show_all ();
676 _notebook_shrunk = false;
678 editor_summary_pane.pack1(edit_packer);
680 Button* summary_arrows_left_left = manage (new Button);
681 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
682 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
683 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
685 Button* summary_arrows_left_right = manage (new Button);
686 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
687 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
688 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
690 VBox* summary_arrows_left = manage (new VBox);
691 summary_arrows_left->pack_start (*summary_arrows_left_left);
692 summary_arrows_left->pack_start (*summary_arrows_left_right);
694 Button* summary_arrows_right_up = manage (new Button);
695 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
696 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
697 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
699 Button* summary_arrows_right_down = manage (new Button);
700 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
701 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
702 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
704 VBox* summary_arrows_right = manage (new VBox);
705 summary_arrows_right->pack_start (*summary_arrows_right_up);
706 summary_arrows_right->pack_start (*summary_arrows_right_down);
708 Frame* summary_frame = manage (new Frame);
709 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
711 summary_frame->add (*_summary);
712 summary_frame->show ();
714 _summary_hbox.pack_start (*summary_arrows_left, false, false);
715 _summary_hbox.pack_start (*summary_frame, true, true);
716 _summary_hbox.pack_start (*summary_arrows_right, false, false);
718 if (!ARDOUR::Profile->get_trx()) {
719 editor_summary_pane.pack2 (_summary_hbox);
722 edit_pane.pack1 (editor_summary_pane, true, true);
723 if (!ARDOUR::Profile->get_trx()) {
724 edit_pane.pack2 (_the_notebook, false, true);
727 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
729 /* XXX: editor_summary_pane might need similar to the edit_pane */
731 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
733 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
734 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
736 top_hbox.pack_start (toolbar_frame);
738 HBox *hbox = manage (new HBox);
739 hbox->pack_start (edit_pane, true, true);
741 global_vpacker.pack_start (top_hbox, false, false);
742 global_vpacker.pack_start (*hbox, true, true);
743 global_hpacker.pack_start (global_vpacker, true, true);
745 /* need to show the "contents" widget so that notebook will show if tab is switched to
748 global_hpacker.show ();
750 /* register actions now so that set_state() can find them and set toggles/checks etc */
757 _playlist_selector = new PlaylistSelector();
758 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
760 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
764 nudge_forward_button.set_name ("nudge button");
765 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
767 nudge_backward_button.set_name ("nudge button");
768 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
770 fade_context_menu.set_name ("ArdourContextMenu");
772 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
774 /* allow external control surfaces/protocols to do various things */
776 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
777 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
778 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
779 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
780 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
781 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
782 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
783 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
784 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
785 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
786 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
787 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
788 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
789 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
791 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
792 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
793 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
794 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
795 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
797 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
799 /* problematic: has to return a value and thus cannot be x-thread */
801 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
803 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
804 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
806 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
808 _ignore_region_action = false;
809 _last_region_menu_was_main = false;
810 _popup_region_menu_item = 0;
812 _ignore_follow_edits = false;
814 _show_marker_lines = false;
816 /* Button bindings */
818 button_bindings = new Bindings ("editor-mouse");
820 XMLNode* node = button_settings();
822 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
823 button_bindings->load_operation (**i);
829 /* grab current parameter state */
830 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
831 UIConfiguration::instance().map_parameters (pc);
833 setup_fade_images ();
840 delete button_bindings;
842 delete _route_groups;
843 delete _track_canvas_viewport;
846 delete quantize_dialog;
852 delete _playlist_selector;
854 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
860 Editor::button_settings () const
862 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
863 XMLNode* node = find_named_node (*settings, X_("Buttons"));
866 node = new XMLNode (X_("Buttons"));
873 Editor::get_smart_mode () const
875 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
879 Editor::catch_vanishing_regionview (RegionView *rv)
881 /* note: the selection will take care of the vanishing
882 audioregionview by itself.
885 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
889 if (clicked_regionview == rv) {
890 clicked_regionview = 0;
893 if (entered_regionview == rv) {
894 set_entered_regionview (0);
897 if (!_all_region_actions_sensitized) {
898 sensitize_all_region_actions (true);
903 Editor::set_entered_regionview (RegionView* rv)
905 if (rv == entered_regionview) {
909 if (entered_regionview) {
910 entered_regionview->exited ();
913 entered_regionview = rv;
915 if (entered_regionview != 0) {
916 entered_regionview->entered ();
919 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
920 /* This RegionView entry might have changed what region actions
921 are allowed, so sensitize them all in case a key is pressed.
923 sensitize_all_region_actions (true);
928 Editor::set_entered_track (TimeAxisView* tav)
931 entered_track->exited ();
937 entered_track->entered ();
942 Editor::instant_save ()
944 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
949 _session->add_instant_xml(get_state());
951 Config->add_instant_xml(get_state());
956 Editor::control_vertical_zoom_in_all ()
958 tav_zoom_smooth (false, true);
962 Editor::control_vertical_zoom_out_all ()
964 tav_zoom_smooth (true, true);
968 Editor::control_vertical_zoom_in_selected ()
970 tav_zoom_smooth (false, false);
974 Editor::control_vertical_zoom_out_selected ()
976 tav_zoom_smooth (true, false);
980 Editor::control_view (uint32_t view)
982 goto_visual_state (view);
986 Editor::control_unselect ()
988 selection->clear_tracks ();
992 Editor::control_select (uint32_t rid, Selection::Operation op)
994 /* handles the (static) signal from the ControlProtocol class that
995 * requests setting the selected track to a given RID
1002 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1008 TimeAxisView* tav = axis_view_from_route (r);
1012 case Selection::Add:
1013 selection->add (tav);
1015 case Selection::Toggle:
1016 selection->toggle (tav);
1018 case Selection::Extend:
1020 case Selection::Set:
1021 selection->set (tav);
1025 selection->clear_tracks ();
1030 Editor::control_step_tracks_up ()
1032 scroll_tracks_up_line ();
1036 Editor::control_step_tracks_down ()
1038 scroll_tracks_down_line ();
1042 Editor::control_scroll (float fraction)
1044 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1050 double step = fraction * current_page_samples();
1053 _control_scroll_target is an optional<T>
1055 it acts like a pointer to an framepos_t, with
1056 a operator conversion to boolean to check
1057 that it has a value could possibly use
1058 playhead_cursor->current_frame to store the
1059 value and a boolean in the class to know
1060 when it's out of date
1063 if (!_control_scroll_target) {
1064 _control_scroll_target = _session->transport_frame();
1065 _dragging_playhead = true;
1068 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1069 *_control_scroll_target = 0;
1070 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1071 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1073 *_control_scroll_target += (framepos_t) trunc (step);
1076 /* move visuals, we'll catch up with it later */
1078 playhead_cursor->set_position (*_control_scroll_target);
1079 UpdateAllTransportClocks (*_control_scroll_target);
1081 if (*_control_scroll_target > (current_page_samples() / 2)) {
1082 /* try to center PH in window */
1083 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1089 Now we do a timeout to actually bring the session to the right place
1090 according to the playhead. This is to avoid reading disk buffers on every
1091 call to control_scroll, which is driven by ScrollTimeline and therefore
1092 probably by a control surface wheel which can generate lots of events.
1094 /* cancel the existing timeout */
1096 control_scroll_connection.disconnect ();
1098 /* add the next timeout */
1100 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1104 Editor::deferred_control_scroll (framepos_t /*target*/)
1106 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1107 // reset for next stream
1108 _control_scroll_target = boost::none;
1109 _dragging_playhead = false;
1114 Editor::access_action (std::string action_group, std::string action_item)
1120 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1123 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1131 Editor::on_realize ()
1135 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1136 start_lock_event_timing ();
1141 Editor::start_lock_event_timing ()
1143 /* check if we should lock the GUI every 30 seconds */
1145 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1149 Editor::generic_event_handler (GdkEvent* ev)
1152 case GDK_BUTTON_PRESS:
1153 case GDK_BUTTON_RELEASE:
1154 case GDK_MOTION_NOTIFY:
1156 case GDK_KEY_RELEASE:
1157 if (contents().is_mapped()) {
1158 gettimeofday (&last_event_time, 0);
1162 case GDK_LEAVE_NOTIFY:
1163 switch (ev->crossing.detail) {
1164 case GDK_NOTIFY_UNKNOWN:
1165 case GDK_NOTIFY_INFERIOR:
1166 case GDK_NOTIFY_ANCESTOR:
1168 case GDK_NOTIFY_VIRTUAL:
1169 case GDK_NOTIFY_NONLINEAR:
1170 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1171 /* leaving window, so reset focus, thus ending any and
1172 all text entry operations.
1187 Editor::lock_timeout_callback ()
1189 struct timeval now, delta;
1191 gettimeofday (&now, 0);
1193 timersub (&now, &last_event_time, &delta);
1195 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1197 /* don't call again. Returning false will effectively
1198 disconnect us from the timer callback.
1200 unlock() will call start_lock_event_timing() to get things
1210 Editor::map_position_change (framepos_t frame)
1212 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1214 if (_session == 0) {
1218 if (_follow_playhead) {
1219 center_screen (frame);
1222 playhead_cursor->set_position (frame);
1226 Editor::center_screen (framepos_t frame)
1228 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1230 /* if we're off the page, then scroll.
1233 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1234 center_screen_internal (frame, page);
1239 Editor::center_screen_internal (framepos_t frame, float page)
1244 frame -= (framepos_t) page;
1249 reset_x_origin (frame);
1254 Editor::update_title ()
1256 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1258 if (!own_window()) {
1263 bool dirty = _session->dirty();
1265 string session_name;
1267 if (_session->snap_name() != _session->name()) {
1268 session_name = _session->snap_name();
1270 session_name = _session->name();
1274 session_name = "*" + session_name;
1277 WindowTitle title(session_name);
1278 title += S_("Window|Editor");
1279 title += Glib::get_application_name();
1280 own_window()->set_title (title.get_string());
1282 /* ::session_going_away() will have taken care of it */
1287 Editor::set_session (Session *t)
1289 SessionHandlePtr::set_session (t);
1295 _playlist_selector->set_session (_session);
1296 nudge_clock->set_session (_session);
1297 _summary->set_session (_session);
1298 _group_tabs->set_session (_session);
1299 _route_groups->set_session (_session);
1300 _regions->set_session (_session);
1301 _snapshots->set_session (_session);
1302 _routes->set_session (_session);
1303 _locations->set_session (_session);
1305 if (rhythm_ferret) {
1306 rhythm_ferret->set_session (_session);
1309 if (analysis_window) {
1310 analysis_window->set_session (_session);
1314 sfbrowser->set_session (_session);
1317 compute_fixed_ruler_scale ();
1319 /* Make sure we have auto loop and auto punch ranges */
1321 Location* loc = _session->locations()->auto_loop_location();
1323 loc->set_name (_("Loop"));
1326 loc = _session->locations()->auto_punch_location();
1329 loc->set_name (_("Punch"));
1332 refresh_location_display ();
1334 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1335 the selected Marker; this needs the LocationMarker list to be available.
1337 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1338 set_state (*node, Stateful::loading_state_version);
1340 /* catch up with the playhead */
1342 _session->request_locate (playhead_cursor->current_frame ());
1343 _pending_initial_locate = true;
1347 /* These signals can all be emitted by a non-GUI thread. Therefore the
1348 handlers for them must not attempt to directly interact with the GUI,
1349 but use PBD::Signal<T>::connect() which accepts an event loop
1350 ("context") where the handler will be asked to run.
1353 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1354 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1355 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1356 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1357 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1358 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1359 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1360 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1361 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1362 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1363 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1364 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1365 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1367 playhead_cursor->show ();
1369 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1370 Config->map_parameters (pc);
1371 _session->config.map_parameters (pc);
1373 restore_ruler_visibility ();
1374 //tempo_map_changed (PropertyChange (0));
1375 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1377 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1378 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1381 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1382 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1385 switch (_snap_type) {
1386 case SnapToRegionStart:
1387 case SnapToRegionEnd:
1388 case SnapToRegionSync:
1389 case SnapToRegionBoundary:
1390 build_region_boundary_cache ();
1397 /* register for undo history */
1398 _session->register_with_memento_command_factory(id(), this);
1399 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1401 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1403 start_updating_meters ();
1407 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1409 if (a->get_name() == "RegionMenu") {
1410 /* When the main menu's region menu is opened, we setup the actions so that they look right
1411 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1412 so we resensitize all region actions when the entered regionview or the region selection
1413 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1414 happens after the region context menu is opened. So we set a flag here, too.
1418 sensitize_the_right_region_actions ();
1419 _last_region_menu_was_main = true;
1424 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1426 using namespace Menu_Helpers;
1428 void (Editor::*emf)(FadeShape);
1429 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1432 images = &_xfade_in_images;
1433 emf = &Editor::set_fade_in_shape;
1435 images = &_xfade_out_images;
1436 emf = &Editor::set_fade_out_shape;
1441 _("Linear (for highly correlated material)"),
1442 *(*images)[FadeLinear],
1443 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1447 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1451 _("Constant power"),
1452 *(*images)[FadeConstantPower],
1453 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1456 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1461 *(*images)[FadeSymmetric],
1462 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1466 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1471 *(*images)[FadeSlow],
1472 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1475 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1480 *(*images)[FadeFast],
1481 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1484 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1487 /** Pop up a context menu for when the user clicks on a start crossfade */
1489 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1491 using namespace Menu_Helpers;
1492 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1497 MenuList& items (xfade_in_context_menu.items());
1500 if (arv->audio_region()->fade_in_active()) {
1501 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1503 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1506 items.push_back (SeparatorElem());
1507 fill_xfade_menu (items, true);
1509 xfade_in_context_menu.popup (button, time);
1512 /** Pop up a context menu for when the user clicks on an end crossfade */
1514 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1516 using namespace Menu_Helpers;
1517 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1522 MenuList& items (xfade_out_context_menu.items());
1525 if (arv->audio_region()->fade_out_active()) {
1526 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1528 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1531 items.push_back (SeparatorElem());
1532 fill_xfade_menu (items, false);
1534 xfade_out_context_menu.popup (button, time);
1538 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1540 using namespace Menu_Helpers;
1541 Menu* (Editor::*build_menu_function)();
1544 switch (item_type) {
1546 case RegionViewName:
1547 case RegionViewNameHighlight:
1548 case LeftFrameHandle:
1549 case RightFrameHandle:
1550 if (with_selection) {
1551 build_menu_function = &Editor::build_track_selection_context_menu;
1553 build_menu_function = &Editor::build_track_region_context_menu;
1558 if (with_selection) {
1559 build_menu_function = &Editor::build_track_selection_context_menu;
1561 build_menu_function = &Editor::build_track_context_menu;
1566 if (clicked_routeview->track()) {
1567 build_menu_function = &Editor::build_track_context_menu;
1569 build_menu_function = &Editor::build_track_bus_context_menu;
1574 /* probably shouldn't happen but if it does, we don't care */
1578 menu = (this->*build_menu_function)();
1579 menu->set_name ("ArdourContextMenu");
1581 /* now handle specific situations */
1583 switch (item_type) {
1585 case RegionViewName:
1586 case RegionViewNameHighlight:
1587 case LeftFrameHandle:
1588 case RightFrameHandle:
1589 if (!with_selection) {
1590 if (region_edit_menu_split_item) {
1591 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1592 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1594 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1597 if (region_edit_menu_split_multichannel_item) {
1598 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1599 region_edit_menu_split_multichannel_item->set_sensitive (true);
1601 region_edit_menu_split_multichannel_item->set_sensitive (false);
1614 /* probably shouldn't happen but if it does, we don't care */
1618 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1620 /* Bounce to disk */
1622 using namespace Menu_Helpers;
1623 MenuList& edit_items = menu->items();
1625 edit_items.push_back (SeparatorElem());
1627 switch (clicked_routeview->audio_track()->freeze_state()) {
1628 case AudioTrack::NoFreeze:
1629 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1632 case AudioTrack::Frozen:
1633 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1636 case AudioTrack::UnFrozen:
1637 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1643 if (item_type == StreamItem && clicked_routeview) {
1644 clicked_routeview->build_underlay_menu(menu);
1647 /* When the region menu is opened, we setup the actions so that they look right
1650 sensitize_the_right_region_actions ();
1651 _last_region_menu_was_main = false;
1653 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1654 menu->popup (button, time);
1658 Editor::build_track_context_menu ()
1660 using namespace Menu_Helpers;
1662 MenuList& edit_items = track_context_menu.items();
1665 add_dstream_context_items (edit_items);
1666 return &track_context_menu;
1670 Editor::build_track_bus_context_menu ()
1672 using namespace Menu_Helpers;
1674 MenuList& edit_items = track_context_menu.items();
1677 add_bus_context_items (edit_items);
1678 return &track_context_menu;
1682 Editor::build_track_region_context_menu ()
1684 using namespace Menu_Helpers;
1685 MenuList& edit_items = track_region_context_menu.items();
1688 /* we've just cleared the track region context menu, so the menu that these
1689 two items were on will have disappeared; stop them dangling.
1691 region_edit_menu_split_item = 0;
1692 region_edit_menu_split_multichannel_item = 0;
1694 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1697 boost::shared_ptr<Track> tr;
1698 boost::shared_ptr<Playlist> pl;
1700 if ((tr = rtv->track())) {
1701 add_region_context_items (edit_items, tr);
1705 add_dstream_context_items (edit_items);
1707 return &track_region_context_menu;
1711 Editor::analyze_region_selection ()
1713 if (analysis_window == 0) {
1714 analysis_window = new AnalysisWindow();
1717 analysis_window->set_session(_session);
1719 analysis_window->show_all();
1722 analysis_window->set_regionmode();
1723 analysis_window->analyze();
1725 analysis_window->present();
1729 Editor::analyze_range_selection()
1731 if (analysis_window == 0) {
1732 analysis_window = new AnalysisWindow();
1735 analysis_window->set_session(_session);
1737 analysis_window->show_all();
1740 analysis_window->set_rangemode();
1741 analysis_window->analyze();
1743 analysis_window->present();
1747 Editor::build_track_selection_context_menu ()
1749 using namespace Menu_Helpers;
1750 MenuList& edit_items = track_selection_context_menu.items();
1751 edit_items.clear ();
1753 add_selection_context_items (edit_items);
1754 // edit_items.push_back (SeparatorElem());
1755 // add_dstream_context_items (edit_items);
1757 return &track_selection_context_menu;
1761 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1763 using namespace Menu_Helpers;
1765 /* OK, stick the region submenu at the top of the list, and then add
1769 RegionSelection rs = get_regions_from_selection_and_entered ();
1771 string::size_type pos = 0;
1772 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1774 /* we have to hack up the region name because "_" has a special
1775 meaning for menu titles.
1778 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1779 menu_item_name.replace (pos, 1, "__");
1783 if (_popup_region_menu_item == 0) {
1784 _popup_region_menu_item = new MenuItem (menu_item_name);
1785 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1786 _popup_region_menu_item->show ();
1788 _popup_region_menu_item->set_label (menu_item_name);
1791 /* No latering allowed in later is higher layering model */
1792 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1793 if (act && Config->get_layer_model() == LaterHigher) {
1794 act->set_sensitive (false);
1796 act->set_sensitive (true);
1799 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1801 edit_items.push_back (*_popup_region_menu_item);
1802 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1803 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1805 edit_items.push_back (SeparatorElem());
1808 /** Add context menu items relevant to selection ranges.
1809 * @param edit_items List to add the items to.
1812 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1814 using namespace Menu_Helpers;
1816 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1817 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1819 edit_items.push_back (SeparatorElem());
1820 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1822 edit_items.push_back (SeparatorElem());
1823 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1825 edit_items.push_back (SeparatorElem());
1827 edit_items.push_back (
1829 _("Move Range Start to Previous Region Boundary"),
1830 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1834 edit_items.push_back (
1836 _("Move Range Start to Next Region Boundary"),
1837 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1841 edit_items.push_back (
1843 _("Move Range End to Previous Region Boundary"),
1844 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1848 edit_items.push_back (
1850 _("Move Range End to Next Region Boundary"),
1851 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1855 edit_items.push_back (SeparatorElem());
1856 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1857 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1859 edit_items.push_back (SeparatorElem());
1860 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1862 edit_items.push_back (SeparatorElem());
1863 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1864 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1865 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1867 edit_items.push_back (SeparatorElem());
1868 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1870 edit_items.push_back (SeparatorElem());
1871 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1872 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1874 edit_items.push_back (SeparatorElem());
1875 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1876 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1877 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1878 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1879 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1880 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1881 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1887 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1889 using namespace Menu_Helpers;
1893 Menu *play_menu = manage (new Menu);
1894 MenuList& play_items = play_menu->items();
1895 play_menu->set_name ("ArdourContextMenu");
1897 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1898 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1899 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1900 play_items.push_back (SeparatorElem());
1901 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1903 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1907 Menu *select_menu = manage (new Menu);
1908 MenuList& select_items = select_menu->items();
1909 select_menu->set_name ("ArdourContextMenu");
1911 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1912 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1913 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1914 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1915 select_items.push_back (SeparatorElem());
1916 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1917 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1918 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
1919 select_items.push_back (SeparatorElem());
1920 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
1921 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
1922 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1923 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1924 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1925 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1926 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1928 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1932 Menu *cutnpaste_menu = manage (new Menu);
1933 MenuList& cutnpaste_items = cutnpaste_menu->items();
1934 cutnpaste_menu->set_name ("ArdourContextMenu");
1936 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1937 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1938 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1940 cutnpaste_items.push_back (SeparatorElem());
1942 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1943 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1945 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1947 /* Adding new material */
1949 edit_items.push_back (SeparatorElem());
1950 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1951 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1955 Menu *nudge_menu = manage (new Menu());
1956 MenuList& nudge_items = nudge_menu->items();
1957 nudge_menu->set_name ("ArdourContextMenu");
1959 edit_items.push_back (SeparatorElem());
1960 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1961 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1962 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1963 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1965 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1969 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1971 using namespace Menu_Helpers;
1975 Menu *play_menu = manage (new Menu);
1976 MenuList& play_items = play_menu->items();
1977 play_menu->set_name ("ArdourContextMenu");
1979 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1980 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1981 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1985 Menu *select_menu = manage (new Menu);
1986 MenuList& select_items = select_menu->items();
1987 select_menu->set_name ("ArdourContextMenu");
1989 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1990 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1991 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1992 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1993 select_items.push_back (SeparatorElem());
1994 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
1995 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
1996 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1997 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1999 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2003 Menu *cutnpaste_menu = manage (new Menu);
2004 MenuList& cutnpaste_items = cutnpaste_menu->items();
2005 cutnpaste_menu->set_name ("ArdourContextMenu");
2007 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2008 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2009 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2011 Menu *nudge_menu = manage (new Menu());
2012 MenuList& nudge_items = nudge_menu->items();
2013 nudge_menu->set_name ("ArdourContextMenu");
2015 edit_items.push_back (SeparatorElem());
2016 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2017 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2018 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2019 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2021 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2025 Editor::snap_type() const
2031 Editor::snap_mode() const
2037 Editor::set_snap_to (SnapType st)
2039 unsigned int snap_ind = (unsigned int)st;
2041 if (internal_editing()) {
2042 internal_snap_type = st;
2044 pre_internal_snap_type = st;
2049 if (snap_ind > snap_type_strings.size() - 1) {
2051 _snap_type = (SnapType)snap_ind;
2054 string str = snap_type_strings[snap_ind];
2056 if (str != snap_type_selector.get_text()) {
2057 snap_type_selector.set_text (str);
2062 switch (_snap_type) {
2063 case SnapToBeatDiv128:
2064 case SnapToBeatDiv64:
2065 case SnapToBeatDiv32:
2066 case SnapToBeatDiv28:
2067 case SnapToBeatDiv24:
2068 case SnapToBeatDiv20:
2069 case SnapToBeatDiv16:
2070 case SnapToBeatDiv14:
2071 case SnapToBeatDiv12:
2072 case SnapToBeatDiv10:
2073 case SnapToBeatDiv8:
2074 case SnapToBeatDiv7:
2075 case SnapToBeatDiv6:
2076 case SnapToBeatDiv5:
2077 case SnapToBeatDiv4:
2078 case SnapToBeatDiv3:
2079 case SnapToBeatDiv2: {
2080 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2081 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2083 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2084 current_bbt_points_begin, current_bbt_points_end);
2085 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2086 current_bbt_points_begin, current_bbt_points_end);
2087 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2091 case SnapToRegionStart:
2092 case SnapToRegionEnd:
2093 case SnapToRegionSync:
2094 case SnapToRegionBoundary:
2095 build_region_boundary_cache ();
2103 redisplay_tempo (false);
2105 SnapChanged (); /* EMIT SIGNAL */
2109 Editor::set_snap_mode (SnapMode mode)
2111 string str = snap_mode_strings[(int)mode];
2113 if (internal_editing()) {
2114 internal_snap_mode = mode;
2116 pre_internal_snap_mode = mode;
2121 if (str != snap_mode_selector.get_text ()) {
2122 snap_mode_selector.set_text (str);
2129 Editor::set_edit_point_preference (EditPoint ep, bool force)
2131 bool changed = (_edit_point != ep);
2134 if (Profile->get_mixbus())
2135 if (ep == EditAtSelectedMarker)
2136 ep = EditAtPlayhead;
2138 string str = edit_point_strings[(int)ep];
2139 if (str != edit_point_selector.get_text ()) {
2140 edit_point_selector.set_text (str);
2143 update_all_enter_cursors();
2145 if (!force && !changed) {
2149 const char* action=NULL;
2151 switch (_edit_point) {
2152 case EditAtPlayhead:
2153 action = "edit-at-playhead";
2155 case EditAtSelectedMarker:
2156 action = "edit-at-marker";
2159 action = "edit-at-mouse";
2163 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2165 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2169 bool in_track_canvas;
2171 if (!mouse_frame (foo, in_track_canvas)) {
2172 in_track_canvas = false;
2175 reset_canvas_action_sensitivity (in_track_canvas);
2181 Editor::set_state (const XMLNode& node, int version)
2183 const XMLProperty* prop;
2186 Tabbable::set_state (node, version);
2188 if (_session && (prop = node.property ("playhead"))) {
2190 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2192 playhead_cursor->set_position (pos);
2194 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2195 playhead_cursor->set_position (0);
2198 playhead_cursor->set_position (0);
2201 if ((prop = node.property ("mixer-width"))) {
2202 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2205 if ((prop = node.property ("zoom-focus"))) {
2206 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2209 if ((prop = node.property ("zoom"))) {
2210 /* older versions of ardour used floating point samples_per_pixel */
2211 double f = PBD::atof (prop->value());
2212 reset_zoom (llrintf (f));
2214 reset_zoom (samples_per_pixel);
2217 if ((prop = node.property ("visible-track-count"))) {
2218 set_visible_track_count (PBD::atoi (prop->value()));
2221 if ((prop = node.property ("snap-to"))) {
2222 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2225 if ((prop = node.property ("snap-mode"))) {
2226 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2229 if ((prop = node.property ("internal-snap-to"))) {
2230 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2233 if ((prop = node.property ("internal-snap-mode"))) {
2234 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2237 if ((prop = node.property ("pre-internal-snap-to"))) {
2238 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2241 if ((prop = node.property ("pre-internal-snap-mode"))) {
2242 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2245 if ((prop = node.property ("mouse-mode"))) {
2246 MouseMode m = str2mousemode(prop->value());
2247 set_mouse_mode (m, true);
2249 set_mouse_mode (MouseObject, true);
2252 if ((prop = node.property ("left-frame")) != 0) {
2254 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2258 reset_x_origin (pos);
2262 if ((prop = node.property ("y-origin")) != 0) {
2263 reset_y_origin (atof (prop->value ()));
2266 if ((prop = node.property ("join-object-range"))) {
2267 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2268 bool yn = string_is_affirmative (prop->value());
2270 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2271 tact->set_active (!yn);
2272 tact->set_active (yn);
2274 set_mouse_mode(mouse_mode, true);
2277 if ((prop = node.property ("edit-point"))) {
2278 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2281 if ((prop = node.property ("show-measures"))) {
2282 bool yn = string_is_affirmative (prop->value());
2283 _show_measures = yn;
2286 if ((prop = node.property ("follow-playhead"))) {
2287 bool yn = string_is_affirmative (prop->value());
2288 set_follow_playhead (yn);
2291 if ((prop = node.property ("stationary-playhead"))) {
2292 bool yn = string_is_affirmative (prop->value());
2293 set_stationary_playhead (yn);
2296 if ((prop = node.property ("region-list-sort-type"))) {
2297 RegionListSortType st;
2298 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2301 if ((prop = node.property ("show-editor-mixer"))) {
2303 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2306 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2307 bool yn = string_is_affirmative (prop->value());
2309 /* do it twice to force the change */
2311 tact->set_active (!yn);
2312 tact->set_active (yn);
2315 if ((prop = node.property ("show-editor-list"))) {
2317 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2320 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2321 bool yn = string_is_affirmative (prop->value());
2323 /* do it twice to force the change */
2325 tact->set_active (!yn);
2326 tact->set_active (yn);
2329 if ((prop = node.property (X_("editor-list-page")))) {
2330 _the_notebook.set_current_page (atoi (prop->value ()));
2333 if ((prop = node.property (X_("show-marker-lines")))) {
2334 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2336 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2337 bool yn = string_is_affirmative (prop->value ());
2339 tact->set_active (!yn);
2340 tact->set_active (yn);
2343 XMLNodeList children = node.children ();
2344 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2345 selection->set_state (**i, Stateful::current_state_version);
2346 _regions->set_state (**i);
2349 if ((prop = node.property ("maximised"))) {
2350 bool yn = string_is_affirmative (prop->value());
2351 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2353 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2354 bool fs = tact && tact->get_active();
2356 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2360 if ((prop = node.property ("nudge-clock-value"))) {
2362 sscanf (prop->value().c_str(), "%" PRId64, &f);
2363 nudge_clock->set (f);
2365 nudge_clock->set_mode (AudioClock::Timecode);
2366 nudge_clock->set (_session->frame_rate() * 5, true);
2371 * Not all properties may have been in XML, but
2372 * those that are linked to a private variable may need changing
2377 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2379 yn = _show_measures;
2380 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2381 /* do it twice to force the change */
2382 tact->set_active (!yn);
2383 tact->set_active (yn);
2386 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2387 yn = _follow_playhead;
2389 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2390 if (tact->get_active() != yn) {
2391 tact->set_active (yn);
2395 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2396 yn = _stationary_playhead;
2398 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2399 if (tact->get_active() != yn) {
2400 tact->set_active (yn);
2409 Editor::get_state ()
2411 XMLNode* node = new XMLNode (X_("Editor"));
2414 id().print (buf, sizeof (buf));
2415 node->add_property ("id", buf);
2417 node->add_child_nocopy (Tabbable::get_state());
2419 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2420 node->add_property("edit-horizontal-pane-pos", string(buf));
2421 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2422 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2423 node->add_property("edit-vertical-pane-pos", string(buf));
2425 maybe_add_mixer_strip_width (*node);
2427 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2429 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2430 node->add_property ("zoom", buf);
2431 node->add_property ("snap-to", enum_2_string (_snap_type));
2432 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2433 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2434 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2435 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2436 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2437 node->add_property ("edit-point", enum_2_string (_edit_point));
2438 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2439 node->add_property ("visible-track-count", buf);
2441 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2442 node->add_property ("playhead", buf);
2443 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2444 node->add_property ("left-frame", buf);
2445 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2446 node->add_property ("y-origin", buf);
2448 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2449 node->add_property ("maximised", _maximised ? "yes" : "no");
2450 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2451 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2452 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2453 node->add_property ("mouse-mode", enum2str(mouse_mode));
2454 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2456 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2458 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2459 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2462 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2464 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2465 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2468 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2469 node->add_property (X_("editor-list-page"), buf);
2471 if (button_bindings) {
2472 XMLNode* bb = new XMLNode (X_("Buttons"));
2473 button_bindings->save (*bb);
2474 node->add_child_nocopy (*bb);
2477 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2479 node->add_child_nocopy (selection->get_state ());
2480 node->add_child_nocopy (_regions->get_state ());
2482 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2483 node->add_property ("nudge-clock-value", buf);
2488 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2489 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2491 * @return pair: TimeAxisView that y is over, layer index.
2493 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2494 * in stacked or expanded region display mode, otherwise 0.
2496 std::pair<TimeAxisView *, double>
2497 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2499 if (!trackview_relative_offset) {
2500 y -= _trackview_group->canvas_origin().y;
2504 return std::make_pair ( (TimeAxisView *) 0, 0);
2507 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2509 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2516 return std::make_pair ( (TimeAxisView *) 0, 0);
2519 /** Snap a position to the grid, if appropriate, taking into account current
2520 * grid settings and also the state of any snap modifier keys that may be pressed.
2521 * @param start Position to snap.
2522 * @param event Event to get current key modifier information from, or 0.
2525 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2527 if (!_session || !event) {
2531 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2532 if (_snap_mode == SnapOff) {
2533 snap_to_internal (start, direction, for_mark);
2536 if (_snap_mode != SnapOff) {
2537 snap_to_internal (start, direction, for_mark);
2538 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2539 /* SnapOff, but we pressed the snap_delta modifier */
2540 snap_to_internal (start, direction, for_mark);
2546 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2548 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2552 snap_to_internal (start, direction, for_mark, ensure_snap);
2556 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2558 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2559 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2561 switch (_snap_type) {
2562 case SnapToTimecodeFrame:
2563 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2564 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2565 /* start is already on a whole timecode frame, do nothing */
2566 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2567 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2569 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2573 case SnapToTimecodeSeconds:
2574 if (_session->config.get_timecode_offset_negative()) {
2575 start += _session->config.get_timecode_offset ();
2577 start -= _session->config.get_timecode_offset ();
2579 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2580 (start % one_timecode_second == 0)) {
2581 /* start is already on a whole second, do nothing */
2582 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2583 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2585 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2588 if (_session->config.get_timecode_offset_negative()) {
2589 start -= _session->config.get_timecode_offset ();
2591 start += _session->config.get_timecode_offset ();
2595 case SnapToTimecodeMinutes:
2596 if (_session->config.get_timecode_offset_negative()) {
2597 start += _session->config.get_timecode_offset ();
2599 start -= _session->config.get_timecode_offset ();
2601 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2602 (start % one_timecode_minute == 0)) {
2603 /* start is already on a whole minute, do nothing */
2604 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2605 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2607 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2609 if (_session->config.get_timecode_offset_negative()) {
2610 start -= _session->config.get_timecode_offset ();
2612 start += _session->config.get_timecode_offset ();
2616 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2617 abort(); /*NOTREACHED*/
2622 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2624 const framepos_t one_second = _session->frame_rate();
2625 const framepos_t one_minute = _session->frame_rate() * 60;
2626 framepos_t presnap = start;
2630 switch (_snap_type) {
2631 case SnapToTimecodeFrame:
2632 case SnapToTimecodeSeconds:
2633 case SnapToTimecodeMinutes:
2634 return timecode_snap_to_internal (start, direction, for_mark);
2637 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2638 start % (one_second/75) == 0) {
2639 /* start is already on a whole CD frame, do nothing */
2640 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2641 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2643 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2648 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2649 start % one_second == 0) {
2650 /* start is already on a whole second, do nothing */
2651 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2652 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2654 start = (framepos_t) floor ((double) start / one_second) * one_second;
2659 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2660 start % one_minute == 0) {
2661 /* start is already on a whole minute, do nothing */
2662 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2663 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2665 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2670 start = _session->tempo_map().round_to_bar (start, direction);
2674 start = _session->tempo_map().round_to_beat (start, direction);
2677 case SnapToBeatDiv128:
2678 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2680 case SnapToBeatDiv64:
2681 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2683 case SnapToBeatDiv32:
2684 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2686 case SnapToBeatDiv28:
2687 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2689 case SnapToBeatDiv24:
2690 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2692 case SnapToBeatDiv20:
2693 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2695 case SnapToBeatDiv16:
2696 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2698 case SnapToBeatDiv14:
2699 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2701 case SnapToBeatDiv12:
2702 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2704 case SnapToBeatDiv10:
2705 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2707 case SnapToBeatDiv8:
2708 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2710 case SnapToBeatDiv7:
2711 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2713 case SnapToBeatDiv6:
2714 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2716 case SnapToBeatDiv5:
2717 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2719 case SnapToBeatDiv4:
2720 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2722 case SnapToBeatDiv3:
2723 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2725 case SnapToBeatDiv2:
2726 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2734 _session->locations()->marks_either_side (start, before, after);
2736 if (before == max_framepos && after == max_framepos) {
2737 /* No marks to snap to, so just don't snap */
2739 } else if (before == max_framepos) {
2741 } else if (after == max_framepos) {
2743 } else if (before != max_framepos && after != max_framepos) {
2744 /* have before and after */
2745 if ((start - before) < (after - start)) {
2754 case SnapToRegionStart:
2755 case SnapToRegionEnd:
2756 case SnapToRegionSync:
2757 case SnapToRegionBoundary:
2758 if (!region_boundary_cache.empty()) {
2760 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2761 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2763 if (direction > 0) {
2764 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2766 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2769 if (next != region_boundary_cache.begin ()) {
2774 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2775 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2777 if (start > (p + n) / 2) {
2786 switch (_snap_mode) {
2796 if (presnap > start) {
2797 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2801 } else if (presnap < start) {
2802 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2808 /* handled at entry */
2816 Editor::setup_toolbar ()
2818 HBox* mode_box = manage(new HBox);
2819 mode_box->set_border_width (2);
2820 mode_box->set_spacing(2);
2822 HBox* mouse_mode_box = manage (new HBox);
2823 HBox* mouse_mode_hbox = manage (new HBox);
2824 VBox* mouse_mode_vbox = manage (new VBox);
2825 Alignment* mouse_mode_align = manage (new Alignment);
2827 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2828 mouse_mode_size_group->add_widget (smart_mode_button);
2829 mouse_mode_size_group->add_widget (mouse_move_button);
2830 mouse_mode_size_group->add_widget (mouse_cut_button);
2831 mouse_mode_size_group->add_widget (mouse_select_button);
2832 mouse_mode_size_group->add_widget (mouse_timefx_button);
2833 mouse_mode_size_group->add_widget (mouse_audition_button);
2834 mouse_mode_size_group->add_widget (mouse_draw_button);
2835 mouse_mode_size_group->add_widget (mouse_content_button);
2837 mouse_mode_size_group->add_widget (zoom_in_button);
2838 mouse_mode_size_group->add_widget (zoom_out_button);
2839 mouse_mode_size_group->add_widget (zoom_preset_selector);
2840 mouse_mode_size_group->add_widget (zoom_out_full_button);
2841 mouse_mode_size_group->add_widget (zoom_focus_selector);
2843 mouse_mode_size_group->add_widget (tav_shrink_button);
2844 mouse_mode_size_group->add_widget (tav_expand_button);
2845 mouse_mode_size_group->add_widget (visible_tracks_selector);
2847 mouse_mode_size_group->add_widget (snap_type_selector);
2848 mouse_mode_size_group->add_widget (snap_mode_selector);
2850 mouse_mode_size_group->add_widget (edit_point_selector);
2851 mouse_mode_size_group->add_widget (edit_mode_selector);
2853 mouse_mode_size_group->add_widget (*nudge_clock);
2854 mouse_mode_size_group->add_widget (nudge_forward_button);
2855 mouse_mode_size_group->add_widget (nudge_backward_button);
2857 mouse_mode_hbox->set_spacing (2);
2859 if (!ARDOUR::Profile->get_trx()) {
2860 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2863 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2864 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2866 if (!ARDOUR::Profile->get_mixbus()) {
2867 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2870 if (!ARDOUR::Profile->get_trx()) {
2871 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2872 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2873 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2874 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2877 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2879 mouse_mode_align->add (*mouse_mode_vbox);
2880 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2882 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2884 edit_mode_selector.set_name ("mouse mode button");
2886 if (!ARDOUR::Profile->get_trx()) {
2887 mode_box->pack_start (edit_mode_selector, false, false);
2890 mode_box->pack_start (*mouse_mode_box, false, false);
2894 _zoom_box.set_spacing (2);
2895 _zoom_box.set_border_width (2);
2899 zoom_preset_selector.set_name ("zoom button");
2900 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2901 zoom_preset_selector.set_size_request (42, -1);
2903 zoom_in_button.set_name ("zoom button");
2904 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
2905 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2906 zoom_in_button.set_related_action (act);
2908 zoom_out_button.set_name ("zoom button");
2909 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
2910 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2911 zoom_out_button.set_related_action (act);
2913 zoom_out_full_button.set_name ("zoom button");
2914 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
2915 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2916 zoom_out_full_button.set_related_action (act);
2918 zoom_focus_selector.set_name ("zoom button");
2920 if (ARDOUR::Profile->get_mixbus()) {
2921 _zoom_box.pack_start (zoom_preset_selector, false, false);
2922 } else if (ARDOUR::Profile->get_trx()) {
2923 mode_box->pack_start (zoom_out_button, false, false);
2924 mode_box->pack_start (zoom_in_button, false, false);
2926 _zoom_box.pack_start (zoom_out_button, false, false);
2927 _zoom_box.pack_start (zoom_in_button, false, false);
2928 _zoom_box.pack_start (zoom_out_full_button, false, false);
2929 _zoom_box.pack_start (zoom_focus_selector, false, false);
2932 /* Track zoom buttons */
2933 visible_tracks_selector.set_name ("zoom button");
2934 if (Profile->get_mixbus()) {
2935 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2936 visible_tracks_selector.set_size_request (42, -1);
2938 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2941 tav_expand_button.set_name ("zoom button");
2942 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
2943 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2944 tav_expand_button.set_related_action (act);
2946 tav_shrink_button.set_name ("zoom button");
2947 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
2948 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2949 tav_shrink_button.set_related_action (act);
2951 if (ARDOUR::Profile->get_mixbus()) {
2952 _zoom_box.pack_start (visible_tracks_selector);
2953 } else if (ARDOUR::Profile->get_trx()) {
2954 _zoom_box.pack_start (tav_shrink_button);
2955 _zoom_box.pack_start (tav_expand_button);
2957 _zoom_box.pack_start (visible_tracks_selector);
2958 _zoom_box.pack_start (tav_shrink_button);
2959 _zoom_box.pack_start (tav_expand_button);
2962 snap_box.set_spacing (2);
2963 snap_box.set_border_width (2);
2965 snap_type_selector.set_name ("mouse mode button");
2967 snap_mode_selector.set_name ("mouse mode button");
2969 edit_point_selector.set_name ("mouse mode button");
2971 snap_box.pack_start (snap_mode_selector, false, false);
2972 snap_box.pack_start (snap_type_selector, false, false);
2973 snap_box.pack_start (edit_point_selector, false, false);
2977 HBox *nudge_box = manage (new HBox);
2978 nudge_box->set_spacing (2);
2979 nudge_box->set_border_width (2);
2981 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2982 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2984 nudge_box->pack_start (nudge_backward_button, false, false);
2985 nudge_box->pack_start (nudge_forward_button, false, false);
2986 nudge_box->pack_start (*nudge_clock, false, false);
2989 /* Pack everything in... */
2991 HBox* hbox = manage (new HBox);
2992 hbox->set_spacing(2);
2994 toolbar_hbox.set_spacing (2);
2995 toolbar_hbox.set_border_width (1);
2997 toolbar_hbox.pack_start (*mode_box, false, false);
2998 if (!ARDOUR::Profile->get_trx()) {
2999 toolbar_hbox.pack_start (_zoom_box, false, false);
3000 toolbar_hbox.pack_start (*hbox, false, false);
3003 if (!ARDOUR::Profile->get_trx()) {
3004 hbox->pack_start (snap_box, false, false);
3005 hbox->pack_start (*nudge_box, false, false);
3010 toolbar_base.set_name ("ToolBarBase");
3011 toolbar_base.add (toolbar_hbox);
3013 _toolbar_viewport.add (toolbar_base);
3014 /* stick to the required height but allow width to vary if there's not enough room */
3015 _toolbar_viewport.set_size_request (1, -1);
3017 toolbar_frame.set_shadow_type (SHADOW_OUT);
3018 toolbar_frame.set_name ("BaseFrame");
3019 toolbar_frame.add (_toolbar_viewport);
3023 Editor::build_edit_point_menu ()
3025 using namespace Menu_Helpers;
3027 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3028 if(!Profile->get_mixbus())
3029 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3030 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3032 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3036 Editor::build_edit_mode_menu ()
3038 using namespace Menu_Helpers;
3040 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3041 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3042 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3043 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3045 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3049 Editor::build_snap_mode_menu ()
3051 using namespace Menu_Helpers;
3053 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3054 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3055 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3057 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3061 Editor::build_snap_type_menu ()
3063 using namespace Menu_Helpers;
3065 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3066 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3067 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3068 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3069 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3070 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3071 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3072 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3073 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3074 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3075 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3076 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3077 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3078 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3079 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3080 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3081 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3082 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3083 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3084 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3085 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3086 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3087 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3088 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3089 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3090 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3091 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3092 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3093 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3094 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3096 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3101 Editor::setup_tooltips ()
3103 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3104 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3105 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3106 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3107 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3108 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3109 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3110 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3111 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3112 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3113 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3114 set_tooltip (zoom_in_button, _("Zoom In"));
3115 set_tooltip (zoom_out_button, _("Zoom Out"));
3116 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3117 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3118 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3119 set_tooltip (tav_expand_button, _("Expand Tracks"));
3120 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3121 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3122 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3123 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3124 set_tooltip (edit_point_selector, _("Edit Point"));
3125 set_tooltip (edit_mode_selector, _("Edit Mode"));
3126 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3130 Editor::convert_drop_to_paths (
3131 vector<string>& paths,
3132 const RefPtr<Gdk::DragContext>& /*context*/,
3135 const SelectionData& data,
3139 if (_session == 0) {
3143 vector<string> uris = data.get_uris();
3147 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3148 are actually URI lists. So do it by hand.
3151 if (data.get_target() != "text/plain") {
3155 /* Parse the "uri-list" format that Nautilus provides,
3156 where each pathname is delimited by \r\n.
3158 THERE MAY BE NO NULL TERMINATING CHAR!!!
3161 string txt = data.get_text();
3165 p = (char *) malloc (txt.length() + 1);
3166 txt.copy (p, txt.length(), 0);
3167 p[txt.length()] = '\0';
3173 while (g_ascii_isspace (*p))
3177 while (*q && (*q != '\n') && (*q != '\r')) {
3184 while (q > p && g_ascii_isspace (*q))
3189 uris.push_back (string (p, q - p + 1));
3193 p = strchr (p, '\n');
3205 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3206 if ((*i).substr (0,7) == "file://") {
3207 paths.push_back (Glib::filename_from_uri (*i));
3215 Editor::new_tempo_section ()
3220 Editor::map_transport_state ()
3222 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3224 if (_session && _session->transport_stopped()) {
3225 have_pending_keyboard_selection = false;
3228 update_loop_range_view ();
3234 Editor::begin_selection_op_history ()
3236 selection_op_cmd_depth = 0;
3237 selection_op_history_it = 0;
3239 while(!selection_op_history.empty()) {
3240 delete selection_op_history.front();
3241 selection_op_history.pop_front();
3244 selection_undo_action->set_sensitive (false);
3245 selection_redo_action->set_sensitive (false);
3246 selection_op_history.push_front (&_selection_memento->get_state ());
3250 Editor::begin_reversible_selection_op (string name)
3253 //cerr << name << endl;
3254 /* begin/commit pairs can be nested */
3255 selection_op_cmd_depth++;
3260 Editor::commit_reversible_selection_op ()
3263 if (selection_op_cmd_depth == 1) {
3265 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3267 The user has undone some selection ops and then made a new one,
3268 making anything earlier in the list invalid.
3271 list<XMLNode *>::iterator it = selection_op_history.begin();
3272 list<XMLNode *>::iterator e_it = it;
3273 advance (e_it, selection_op_history_it);
3275 for ( ; it != e_it; ++it) {
3278 selection_op_history.erase (selection_op_history.begin(), e_it);
3281 selection_op_history.push_front (&_selection_memento->get_state ());
3282 selection_op_history_it = 0;
3284 selection_undo_action->set_sensitive (true);
3285 selection_redo_action->set_sensitive (false);
3288 if (selection_op_cmd_depth > 0) {
3289 selection_op_cmd_depth--;
3295 Editor::undo_selection_op ()
3298 selection_op_history_it++;
3300 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3301 if (n == selection_op_history_it) {
3302 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3303 selection_redo_action->set_sensitive (true);
3307 /* is there an earlier entry? */
3308 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3309 selection_undo_action->set_sensitive (false);
3315 Editor::redo_selection_op ()
3318 if (selection_op_history_it > 0) {
3319 selection_op_history_it--;
3322 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3323 if (n == selection_op_history_it) {
3324 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3325 selection_undo_action->set_sensitive (true);
3330 if (selection_op_history_it == 0) {
3331 selection_redo_action->set_sensitive (false);
3337 Editor::begin_reversible_command (string name)
3340 before.push_back (&_selection_memento->get_state ());
3341 _session->begin_reversible_command (name);
3346 Editor::begin_reversible_command (GQuark q)
3349 before.push_back (&_selection_memento->get_state ());
3350 _session->begin_reversible_command (q);
3355 Editor::abort_reversible_command ()
3358 while(!before.empty()) {
3359 delete before.front();
3362 _session->abort_reversible_command ();
3367 Editor::commit_reversible_command ()
3370 if (before.size() == 1) {
3371 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3372 redo_action->set_sensitive(false);
3373 undo_action->set_sensitive(true);
3374 begin_selection_op_history ();
3377 if (before.empty()) {
3378 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3383 _session->commit_reversible_command ();
3388 Editor::history_changed ()
3392 if (undo_action && _session) {
3393 if (_session->undo_depth() == 0) {
3394 label = S_("Command|Undo");
3396 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3398 undo_action->property_label() = label;
3401 if (redo_action && _session) {
3402 if (_session->redo_depth() == 0) {
3404 redo_action->set_sensitive (false);
3406 label = string_compose(_("Redo (%1)"), _session->next_redo());
3407 redo_action->set_sensitive (true);
3409 redo_action->property_label() = label;
3414 Editor::duplicate_range (bool with_dialog)
3418 RegionSelection rs = get_regions_from_selection_and_entered ();
3420 if ( selection->time.length() == 0 && rs.empty()) {
3426 ArdourDialog win (_("Duplicate"));
3427 Label label (_("Number of duplications:"));
3428 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3429 SpinButton spinner (adjustment, 0.0, 1);
3432 win.get_vbox()->set_spacing (12);
3433 win.get_vbox()->pack_start (hbox);
3434 hbox.set_border_width (6);
3435 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3437 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3438 place, visually. so do this by hand.
3441 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3442 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3443 spinner.grab_focus();
3449 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3450 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3451 win.set_default_response (RESPONSE_ACCEPT);
3453 spinner.grab_focus ();
3455 switch (win.run ()) {
3456 case RESPONSE_ACCEPT:
3462 times = adjustment.get_value();
3465 if ((current_mouse_mode() == Editing::MouseRange)) {
3466 if (selection->time.length()) {
3467 duplicate_selection (times);
3469 } else if (get_smart_mode()) {
3470 if (selection->time.length()) {
3471 duplicate_selection (times);
3473 duplicate_some_regions (rs, times);
3475 duplicate_some_regions (rs, times);
3480 Editor::set_edit_mode (EditMode m)
3482 Config->set_edit_mode (m);
3486 Editor::cycle_edit_mode ()
3488 switch (Config->get_edit_mode()) {
3490 Config->set_edit_mode (Ripple);
3494 Config->set_edit_mode (Lock);
3497 Config->set_edit_mode (Slide);
3503 Editor::edit_mode_selection_done ( EditMode m )
3505 Config->set_edit_mode ( m );
3509 Editor::snap_type_selection_done (SnapType snaptype)
3511 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3513 ract->set_active ();
3518 Editor::snap_mode_selection_done (SnapMode mode)
3520 RefPtr<RadioAction> ract = snap_mode_action (mode);
3523 ract->set_active (true);
3528 Editor::cycle_edit_point (bool with_marker)
3530 if(Profile->get_mixbus())
3531 with_marker = false;
3533 switch (_edit_point) {
3535 set_edit_point_preference (EditAtPlayhead);
3537 case EditAtPlayhead:
3539 set_edit_point_preference (EditAtSelectedMarker);
3541 set_edit_point_preference (EditAtMouse);
3544 case EditAtSelectedMarker:
3545 set_edit_point_preference (EditAtMouse);
3551 Editor::edit_point_selection_done (EditPoint ep)
3553 set_edit_point_preference ( ep );
3557 Editor::build_zoom_focus_menu ()
3559 using namespace Menu_Helpers;
3561 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3562 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3563 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3564 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3565 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3566 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3568 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3572 Editor::zoom_focus_selection_done ( ZoomFocus f )
3574 RefPtr<RadioAction> ract = zoom_focus_action (f);
3576 ract->set_active ();
3581 Editor::build_track_count_menu ()
3583 using namespace Menu_Helpers;
3585 if (!Profile->get_mixbus()) {
3586 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3587 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3588 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3589 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3590 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3591 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3592 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3593 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3594 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3595 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3596 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3597 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3598 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3600 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3601 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3602 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3603 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3604 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3605 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3606 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3607 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3608 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3609 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3611 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3612 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3613 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3614 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3615 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3616 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3617 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3618 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3619 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3620 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3621 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3626 Editor::set_zoom_preset (int64_t ms)
3629 temporal_zoom_session();
3633 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3634 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3638 Editor::set_visible_track_count (int32_t n)
3640 _visible_track_count = n;
3642 /* if the canvas hasn't really been allocated any size yet, just
3643 record the desired number of visible tracks and return. when canvas
3644 allocation happens, we will get called again and then we can do the
3648 if (_visible_canvas_height <= 1) {
3654 DisplaySuspender ds;
3656 if (_visible_track_count > 0) {
3657 h = trackviews_height() / _visible_track_count;
3658 std::ostringstream s;
3659 s << _visible_track_count;
3661 } else if (_visible_track_count == 0) {
3663 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3664 if ((*i)->marked_for_display()) {
3668 h = trackviews_height() / n;
3671 /* negative value means that the visible track count has
3672 been overridden by explicit track height changes.
3674 visible_tracks_selector.set_text (X_("*"));
3678 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3679 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3682 if (str != visible_tracks_selector.get_text()) {
3683 visible_tracks_selector.set_text (str);
3688 Editor::override_visible_track_count ()
3690 _visible_track_count = -1;
3691 visible_tracks_selector.set_text ( _("*") );
3695 Editor::edit_controls_button_release (GdkEventButton* ev)
3697 if (Keyboard::is_context_menu_event (ev)) {
3698 ARDOUR_UI::instance()->add_route (current_toplevel());
3699 } else if (ev->button == 1) {
3700 selection->clear_tracks ();
3707 Editor::mouse_select_button_release (GdkEventButton* ev)
3709 /* this handles just right-clicks */
3711 if (ev->button != 3) {
3719 Editor::set_zoom_focus (ZoomFocus f)
3721 string str = zoom_focus_strings[(int)f];
3723 if (str != zoom_focus_selector.get_text()) {
3724 zoom_focus_selector.set_text (str);
3727 if (zoom_focus != f) {
3734 Editor::cycle_zoom_focus ()
3736 switch (zoom_focus) {
3738 set_zoom_focus (ZoomFocusRight);
3740 case ZoomFocusRight:
3741 set_zoom_focus (ZoomFocusCenter);
3743 case ZoomFocusCenter:
3744 set_zoom_focus (ZoomFocusPlayhead);
3746 case ZoomFocusPlayhead:
3747 set_zoom_focus (ZoomFocusMouse);
3749 case ZoomFocusMouse:
3750 set_zoom_focus (ZoomFocusEdit);
3753 set_zoom_focus (ZoomFocusLeft);
3759 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3761 /* recover or initialize pane positions. do this here rather than earlier because
3762 we don't want the positions to change the child allocations, which they seem to do.
3768 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3777 XMLNode* geometry = find_named_node (*node, "geometry");
3779 if (which == static_cast<Paned*> (&edit_pane)) {
3781 if (done & Horizontal) {
3785 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3786 _notebook_shrunk = string_is_affirmative (prop->value ());
3789 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3790 /* initial allocation is 90% to canvas, 10% to notebook */
3791 pos = (int) floor (alloc.get_width() * 0.90f);
3792 snprintf (buf, sizeof(buf), "%d", pos);
3794 pos = atoi (prop->value());
3797 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3798 edit_pane.set_position (pos);
3801 done = (Pane) (done | Horizontal);
3803 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3805 if (done & Vertical) {
3809 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3810 /* initial allocation is 90% to canvas, 10% to summary */
3811 pos = (int) floor (alloc.get_height() * 0.90f);
3812 snprintf (buf, sizeof(buf), "%d", pos);
3815 pos = atoi (prop->value());
3818 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3819 editor_summary_pane.set_position (pos);
3822 done = (Pane) (done | Vertical);
3827 Editor::set_show_measures (bool yn)
3829 if (_show_measures != yn) {
3832 if ((_show_measures = yn) == true) {
3834 tempo_lines->show();
3837 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3838 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3840 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3841 draw_measures (begin, end);
3849 Editor::toggle_follow_playhead ()
3851 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3853 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3854 set_follow_playhead (tact->get_active());
3858 /** @param yn true to follow playhead, otherwise false.
3859 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3862 Editor::set_follow_playhead (bool yn, bool catch_up)
3864 if (_follow_playhead != yn) {
3865 if ((_follow_playhead = yn) == true && catch_up) {
3867 reset_x_origin_to_follow_playhead ();
3874 Editor::toggle_stationary_playhead ()
3876 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3878 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3879 set_stationary_playhead (tact->get_active());
3884 Editor::set_stationary_playhead (bool yn)
3886 if (_stationary_playhead != yn) {
3887 if ((_stationary_playhead = yn) == true) {
3889 // FIXME need a 3.0 equivalent of this 2.X call
3890 // update_current_screen ();
3897 Editor::playlist_selector () const
3899 return *_playlist_selector;
3903 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
3905 if (paste_count == 0) {
3906 /* don't bother calculating an offset that will be zero anyway */
3910 /* calculate basic unsnapped multi-paste offset */
3911 framecnt_t offset = paste_count * duration;
3913 /* snap offset so pos + offset is aligned to the grid */
3914 framepos_t offset_pos = pos + offset;
3915 snap_to(offset_pos, RoundUpMaybe);
3916 offset = offset_pos - pos;
3922 Editor::get_grid_beat_divisions(framepos_t position)
3924 switch (_snap_type) {
3925 case SnapToBeatDiv128: return 128;
3926 case SnapToBeatDiv64: return 64;
3927 case SnapToBeatDiv32: return 32;
3928 case SnapToBeatDiv28: return 28;
3929 case SnapToBeatDiv24: return 24;
3930 case SnapToBeatDiv20: return 20;
3931 case SnapToBeatDiv16: return 16;
3932 case SnapToBeatDiv14: return 14;
3933 case SnapToBeatDiv12: return 12;
3934 case SnapToBeatDiv10: return 10;
3935 case SnapToBeatDiv8: return 8;
3936 case SnapToBeatDiv7: return 7;
3937 case SnapToBeatDiv6: return 6;
3938 case SnapToBeatDiv5: return 5;
3939 case SnapToBeatDiv4: return 4;
3940 case SnapToBeatDiv3: return 3;
3941 case SnapToBeatDiv2: return 2;
3948 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3952 const unsigned divisions = get_grid_beat_divisions(position);
3954 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
3957 switch (_snap_type) {
3959 return Evoral::Beats(1.0);
3962 return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
3970 return Evoral::Beats();
3974 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3978 ret = nudge_clock->current_duration (pos);
3979 next = ret + 1; /* XXXX fix me */
3985 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3987 ArdourDialog dialog (_("Playlist Deletion"));
3988 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3989 "If it is kept, its audio files will not be cleaned.\n"
3990 "If it is deleted, audio files used by it alone will be cleaned."),
3993 dialog.set_position (WIN_POS_CENTER);
3994 dialog.get_vbox()->pack_start (label);
3998 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
3999 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4000 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4001 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4002 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4004 // by default gtk uses the left most button
4005 keep->grab_focus ();
4007 switch (dialog.run ()) {
4009 /* keep this and all remaining ones */
4014 /* delete this and all others */
4018 case RESPONSE_ACCEPT:
4019 /* delete the playlist */
4023 case RESPONSE_REJECT:
4024 /* keep the playlist */
4036 Editor::audio_region_selection_covers (framepos_t where)
4038 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4039 if ((*a)->region()->covers (where)) {
4048 Editor::prepare_for_cleanup ()
4050 cut_buffer->clear_regions ();
4051 cut_buffer->clear_playlists ();
4053 selection->clear_regions ();
4054 selection->clear_playlists ();
4056 _regions->suspend_redisplay ();
4060 Editor::finish_cleanup ()
4062 _regions->resume_redisplay ();
4066 Editor::transport_loop_location()
4069 return _session->locations()->auto_loop_location();
4076 Editor::transport_punch_location()
4079 return _session->locations()->auto_punch_location();
4086 Editor::control_layout_scroll (GdkEventScroll* ev)
4088 /* Just forward to the normal canvas scroll method. The coordinate
4089 systems are different but since the canvas is always larger than the
4090 track headers, and aligned with the trackview area, this will work.
4092 In the not too distant future this layout is going away anyway and
4093 headers will be on the canvas.
4095 return canvas_scroll_event (ev, false);
4099 Editor::session_state_saved (string)
4102 _snapshots->redisplay ();
4106 Editor::maximise_editing_space ()
4112 Gtk::Window* toplevel = current_toplevel();
4115 toplevel->fullscreen ();
4121 Editor::restore_editing_space ()
4127 Gtk::Window* toplevel = current_toplevel();
4130 toplevel->unfullscreen();
4136 * Make new playlists for a given track and also any others that belong
4137 * to the same active route group with the `select' property.
4142 Editor::new_playlists (TimeAxisView* v)
4144 begin_reversible_command (_("new playlists"));
4145 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4146 _session->playlists->get (playlists);
4147 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4148 commit_reversible_command ();
4152 * Use a copy of the current playlist for a given track and also any others that belong
4153 * to the same active route group with the `select' property.
4158 Editor::copy_playlists (TimeAxisView* v)
4160 begin_reversible_command (_("copy playlists"));
4161 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4162 _session->playlists->get (playlists);
4163 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4164 commit_reversible_command ();
4167 /** Clear the current playlist for a given track and also any others that belong
4168 * to the same active route group with the `select' property.
4173 Editor::clear_playlists (TimeAxisView* v)
4175 begin_reversible_command (_("clear playlists"));
4176 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4177 _session->playlists->get (playlists);
4178 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4179 commit_reversible_command ();
4183 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4185 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4189 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4191 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4195 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4197 atv.clear_playlist ();
4201 Editor::get_y_origin () const
4203 return vertical_adjustment.get_value ();
4206 /** Queue up a change to the viewport x origin.
4207 * @param frame New x origin.
4210 Editor::reset_x_origin (framepos_t frame)
4212 pending_visual_change.add (VisualChange::TimeOrigin);
4213 pending_visual_change.time_origin = frame;
4214 ensure_visual_change_idle_handler ();
4218 Editor::reset_y_origin (double y)
4220 pending_visual_change.add (VisualChange::YOrigin);
4221 pending_visual_change.y_origin = y;
4222 ensure_visual_change_idle_handler ();
4226 Editor::reset_zoom (framecnt_t spp)
4228 if (spp == samples_per_pixel) {
4232 pending_visual_change.add (VisualChange::ZoomLevel);
4233 pending_visual_change.samples_per_pixel = spp;
4234 ensure_visual_change_idle_handler ();
4238 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4240 reset_x_origin (frame);
4243 if (!no_save_visual) {
4244 undo_visual_stack.push_back (current_visual_state(false));
4248 Editor::VisualState::VisualState (bool with_tracks)
4249 : gui_state (with_tracks ? new GUIObjectState : 0)
4253 Editor::VisualState::~VisualState ()
4258 Editor::VisualState*
4259 Editor::current_visual_state (bool with_tracks)
4261 VisualState* vs = new VisualState (with_tracks);
4262 vs->y_position = vertical_adjustment.get_value();
4263 vs->samples_per_pixel = samples_per_pixel;
4264 vs->leftmost_frame = leftmost_frame;
4265 vs->zoom_focus = zoom_focus;
4268 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4275 Editor::undo_visual_state ()
4277 if (undo_visual_stack.empty()) {
4281 VisualState* vs = undo_visual_stack.back();
4282 undo_visual_stack.pop_back();
4285 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4288 use_visual_state (*vs);
4293 Editor::redo_visual_state ()
4295 if (redo_visual_stack.empty()) {
4299 VisualState* vs = redo_visual_stack.back();
4300 redo_visual_stack.pop_back();
4302 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4303 // why do we check here?
4304 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4307 use_visual_state (*vs);
4312 Editor::swap_visual_state ()
4314 if (undo_visual_stack.empty()) {
4315 redo_visual_state ();
4317 undo_visual_state ();
4322 Editor::use_visual_state (VisualState& vs)
4324 PBD::Unwinder<bool> nsv (no_save_visual, true);
4325 DisplaySuspender ds;
4327 vertical_adjustment.set_value (vs.y_position);
4329 set_zoom_focus (vs.zoom_focus);
4330 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4333 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4335 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4336 (*i)->clear_property_cache();
4337 (*i)->reset_visual_state ();
4341 _routes->update_visibility ();
4344 /** This is the core function that controls the zoom level of the canvas. It is called
4345 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4346 * @param spp new number of samples per pixel
4349 Editor::set_samples_per_pixel (framecnt_t spp)
4355 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4356 const framecnt_t lots_of_pixels = 4000;
4358 /* if the zoom level is greater than what you'd get trying to display 3
4359 * days of audio on a really big screen, then it's too big.
4362 if (spp * lots_of_pixels > three_days) {
4366 samples_per_pixel = spp;
4369 tempo_lines->tempo_map_changed();
4372 bool const showing_time_selection = selection->time.length() > 0;
4374 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4375 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4376 (*i)->reshow_selection (selection->time);
4380 ZoomChanged (); /* EMIT_SIGNAL */
4382 ArdourCanvas::GtkCanvasViewport* c;
4384 c = get_track_canvas();
4386 c->canvas()->zoomed ();
4389 if (playhead_cursor) {
4390 playhead_cursor->set_position (playhead_cursor->current_frame ());
4393 refresh_location_display();
4394 _summary->set_overlays_dirty ();
4396 update_marker_labels ();
4402 Editor::queue_visual_videotimeline_update ()
4405 * pending_visual_change.add (VisualChange::VideoTimeline);
4406 * or maybe even more specific: which videotimeline-image
4407 * currently it calls update_video_timeline() to update
4408 * _all outdated_ images on the video-timeline.
4409 * see 'exposeimg()' in video_image_frame.cc
4411 ensure_visual_change_idle_handler ();
4415 Editor::ensure_visual_change_idle_handler ()
4417 if (pending_visual_change.idle_handler_id < 0) {
4418 // see comment in add_to_idle_resize above.
4419 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4420 pending_visual_change.being_handled = false;
4425 Editor::_idle_visual_changer (void* arg)
4427 return static_cast<Editor*>(arg)->idle_visual_changer ();
4431 Editor::idle_visual_changer ()
4433 /* set_horizontal_position() below (and maybe other calls) call
4434 gtk_main_iteration(), so it's possible that a signal will be handled
4435 half-way through this method. If this signal wants an
4436 idle_visual_changer we must schedule another one after this one, so
4437 mark the idle_handler_id as -1 here to allow that. Also make a note
4438 that we are doing the visual change, so that changes in response to
4439 super-rapid-screen-update can be dropped if we are still processing
4443 pending_visual_change.idle_handler_id = -1;
4444 pending_visual_change.being_handled = true;
4446 VisualChange vc = pending_visual_change;
4448 pending_visual_change.pending = (VisualChange::Type) 0;
4450 visual_changer (vc);
4452 pending_visual_change.being_handled = false;
4454 return 0; /* this is always a one-shot call */
4458 Editor::visual_changer (const VisualChange& vc)
4460 double const last_time_origin = horizontal_position ();
4462 if (vc.pending & VisualChange::ZoomLevel) {
4463 set_samples_per_pixel (vc.samples_per_pixel);
4465 compute_fixed_ruler_scale ();
4467 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4468 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4470 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4471 current_bbt_points_begin, current_bbt_points_end);
4472 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4473 current_bbt_points_begin, current_bbt_points_end);
4474 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4476 update_video_timeline();
4479 if (vc.pending & VisualChange::TimeOrigin) {
4480 set_horizontal_position (vc.time_origin / samples_per_pixel);
4483 if (vc.pending & VisualChange::YOrigin) {
4484 vertical_adjustment.set_value (vc.y_origin);
4487 if (last_time_origin == horizontal_position ()) {
4488 /* changed signal not emitted */
4489 update_fixed_rulers ();
4490 redisplay_tempo (true);
4493 if (!(vc.pending & VisualChange::ZoomLevel)) {
4494 update_video_timeline();
4497 _summary->set_overlays_dirty ();
4500 struct EditorOrderTimeAxisSorter {
4501 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4502 return a->order () < b->order ();
4507 Editor::sort_track_selection (TrackViewList& sel)
4509 EditorOrderTimeAxisSorter cmp;
4514 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4517 framepos_t where = 0;
4518 EditPoint ep = _edit_point;
4520 if (Profile->get_mixbus())
4521 if (ep == EditAtSelectedMarker)
4522 ep = EditAtPlayhead;
4524 if (from_outside_canvas && (ep == EditAtMouse)) {
4525 ep = EditAtPlayhead;
4526 } else if (from_context_menu && (ep == EditAtMouse)) {
4527 return canvas_event_sample (&context_click_event, 0, 0);
4530 if (entered_marker) {
4531 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4532 return entered_marker->position();
4535 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4536 ep = EditAtSelectedMarker;
4539 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4540 ep = EditAtPlayhead;
4544 case EditAtPlayhead:
4545 if (_dragging_playhead) {
4546 where = *_control_scroll_target;
4548 where = _session->audible_frame();
4550 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4553 case EditAtSelectedMarker:
4554 if (!selection->markers.empty()) {
4556 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4559 where = loc->start();
4563 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4571 if (!mouse_frame (where, ignored)) {
4572 /* XXX not right but what can we do ? */
4576 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4584 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4586 if (!_session) return;
4588 begin_reversible_command (cmd);
4592 if ((tll = transport_loop_location()) == 0) {
4593 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4594 XMLNode &before = _session->locations()->get_state();
4595 _session->locations()->add (loc, true);
4596 _session->set_auto_loop_location (loc);
4597 XMLNode &after = _session->locations()->get_state();
4598 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4600 XMLNode &before = tll->get_state();
4601 tll->set_hidden (false, this);
4602 tll->set (start, end);
4603 XMLNode &after = tll->get_state();
4604 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4607 commit_reversible_command ();
4611 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4613 if (!_session) return;
4615 begin_reversible_command (cmd);
4619 if ((tpl = transport_punch_location()) == 0) {
4620 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4621 XMLNode &before = _session->locations()->get_state();
4622 _session->locations()->add (loc, true);
4623 _session->set_auto_punch_location (loc);
4624 XMLNode &after = _session->locations()->get_state();
4625 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4627 XMLNode &before = tpl->get_state();
4628 tpl->set_hidden (false, this);
4629 tpl->set (start, end);
4630 XMLNode &after = tpl->get_state();
4631 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4634 commit_reversible_command ();
4637 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4638 * @param rs List to which found regions are added.
4639 * @param where Time to look at.
4640 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4643 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4645 const TrackViewList* tracks;
4648 tracks = &track_views;
4653 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4655 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4658 boost::shared_ptr<Track> tr;
4659 boost::shared_ptr<Playlist> pl;
4661 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4663 boost::shared_ptr<RegionList> regions = pl->regions_at (
4664 (framepos_t) floor ( (double) where * tr->speed()));
4666 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4667 RegionView* rv = rtv->view()->find_view (*i);
4678 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4680 const TrackViewList* tracks;
4683 tracks = &track_views;
4688 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4689 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4691 boost::shared_ptr<Track> tr;
4692 boost::shared_ptr<Playlist> pl;
4694 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4696 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4697 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4699 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4701 RegionView* rv = rtv->view()->find_view (*i);
4712 /** Get regions using the following method:
4714 * Make a region list using:
4715 * (a) any selected regions
4716 * (b) the intersection of any selected tracks and the edit point(*)
4717 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4719 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4721 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4725 Editor::get_regions_from_selection_and_edit_point ()
4727 RegionSelection regions;
4729 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4730 regions.add (entered_regionview);
4732 regions = selection->regions;
4735 if ( regions.empty() ) {
4736 TrackViewList tracks = selection->tracks;
4738 if (!tracks.empty()) {
4739 /* no region selected or entered, but some selected tracks:
4740 * act on all regions on the selected tracks at the edit point
4742 framepos_t const where = get_preferred_edit_position ();
4743 get_regions_at(regions, where, tracks);
4750 /** Get regions using the following method:
4752 * Make a region list using:
4753 * (a) any selected regions
4754 * (b) the intersection of any selected tracks and the edit point(*)
4755 * (c) if neither exists, then whatever region is under the mouse
4757 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4759 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4762 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4764 RegionSelection regions;
4766 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4767 regions.add (entered_regionview);
4769 regions = selection->regions;
4772 if ( regions.empty() ) {
4773 TrackViewList tracks = selection->tracks;
4775 if (!tracks.empty()) {
4776 /* no region selected or entered, but some selected tracks:
4777 * act on all regions on the selected tracks at the edit point
4779 get_regions_at(regions, pos, tracks);
4786 /** Start with regions that are selected, or the entered regionview if none are selected.
4787 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4788 * of the regions that we started with.
4792 Editor::get_regions_from_selection_and_entered ()
4794 RegionSelection regions = selection->regions;
4796 if (regions.empty() && entered_regionview) {
4797 regions.add (entered_regionview);
4804 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4806 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4807 RouteTimeAxisView* rtav;
4809 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4810 boost::shared_ptr<Playlist> pl;
4811 std::vector<boost::shared_ptr<Region> > results;
4812 boost::shared_ptr<Track> tr;
4814 if ((tr = rtav->track()) == 0) {
4819 if ((pl = (tr->playlist())) != 0) {
4820 boost::shared_ptr<Region> r = pl->region_by_id (id);
4822 RegionView* rv = rtav->view()->find_view (r);
4824 regions.push_back (rv);
4833 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4836 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4837 MidiTimeAxisView* mtav;
4839 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4841 mtav->get_per_region_note_selection (selection);
4848 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4850 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4852 RouteTimeAxisView* tatv;
4854 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4856 boost::shared_ptr<Playlist> pl;
4857 vector<boost::shared_ptr<Region> > results;
4859 boost::shared_ptr<Track> tr;
4861 if ((tr = tatv->track()) == 0) {
4866 if ((pl = (tr->playlist())) != 0) {
4867 if (src_comparison) {
4868 pl->get_source_equivalent_regions (region, results);
4870 pl->get_region_list_equivalent_regions (region, results);
4874 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4875 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4876 regions.push_back (marv);
4885 Editor::show_rhythm_ferret ()
4887 if (rhythm_ferret == 0) {
4888 rhythm_ferret = new RhythmFerret(*this);
4891 rhythm_ferret->set_session (_session);
4892 rhythm_ferret->show ();
4893 rhythm_ferret->present ();
4897 Editor::first_idle ()
4899 MessageDialog* dialog = 0;
4901 if (track_views.size() > 1) {
4902 Timers::TimerSuspender t;
4903 dialog = new MessageDialog (
4904 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4908 ARDOUR_UI::instance()->flush_pending ();
4911 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4915 // first idle adds route children (automation tracks), so we need to redisplay here
4916 _routes->redisplay ();
4920 if (_session->undo_depth() == 0) {
4921 undo_action->set_sensitive(false);
4923 redo_action->set_sensitive(false);
4924 begin_selection_op_history ();
4930 Editor::_idle_resize (gpointer arg)
4932 return ((Editor*)arg)->idle_resize ();
4936 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4938 if (resize_idle_id < 0) {
4939 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
4940 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
4941 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
4943 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
4944 _pending_resize_amount = 0;
4947 /* make a note of the smallest resulting height, so that we can clamp the
4948 lower limit at TimeAxisView::hSmall */
4950 int32_t min_resulting = INT32_MAX;
4952 _pending_resize_amount += h;
4953 _pending_resize_view = view;
4955 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4957 if (selection->tracks.contains (_pending_resize_view)) {
4958 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4959 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4963 if (min_resulting < 0) {
4968 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4969 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4973 /** Handle pending resizing of tracks */
4975 Editor::idle_resize ()
4977 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4979 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4980 selection->tracks.contains (_pending_resize_view)) {
4982 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4983 if (*i != _pending_resize_view) {
4984 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4989 _pending_resize_amount = 0;
4990 _group_tabs->set_dirty ();
4991 resize_idle_id = -1;
4999 ENSURE_GUI_THREAD (*this, &Editor::located);
5002 playhead_cursor->set_position (_session->audible_frame ());
5003 if (_follow_playhead && !_pending_initial_locate) {
5004 reset_x_origin_to_follow_playhead ();
5008 _pending_locate_request = false;
5009 _pending_initial_locate = false;
5013 Editor::region_view_added (RegionView * rv)
5015 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5016 if (rv->region ()->id () == (*pr)) {
5017 selection->add (rv);
5018 selection->regions.pending.erase (pr);
5023 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5025 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5026 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5027 if (rv->region()->id () == (*rnote).first) {
5028 mrv->select_notes ((*rnote).second);
5029 selection->pending_midi_note_selection.erase(rnote);
5035 _summary->set_background_dirty ();
5039 Editor::region_view_removed ()
5041 _summary->set_background_dirty ();
5045 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5047 TrackViewList::const_iterator j = track_views.begin ();
5048 while (j != track_views.end()) {
5049 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5050 if (rtv && rtv->route() == r) {
5061 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5065 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5066 TimeAxisView* tv = axis_view_from_route (*i);
5076 Editor::suspend_route_redisplay ()
5079 _routes->suspend_redisplay();
5084 Editor::resume_route_redisplay ()
5087 _routes->redisplay(); // queue redisplay
5088 _routes->resume_redisplay();
5093 Editor::add_routes (RouteList& routes)
5095 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5097 RouteTimeAxisView *rtv;
5098 list<RouteTimeAxisView*> new_views;
5099 TrackViewList new_selection;
5100 bool from_scratch = (track_views.size() == 0);
5102 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5103 boost::shared_ptr<Route> route = (*x);
5105 if (route->is_auditioner() || route->is_monitor()) {
5109 DataType dt = route->input()->default_type();
5111 if (dt == ARDOUR::DataType::AUDIO) {
5112 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5113 rtv->set_route (route);
5114 } else if (dt == ARDOUR::DataType::MIDI) {
5115 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5116 rtv->set_route (route);
5118 throw unknown_type();
5121 new_views.push_back (rtv);
5122 track_views.push_back (rtv);
5123 new_selection.push_back (rtv);
5125 rtv->effective_gain_display ();
5127 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5128 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5131 if (new_views.size() > 0) {
5132 _routes->routes_added (new_views);
5133 _summary->routes_added (new_views);
5136 if (!from_scratch) {
5137 selection->tracks.clear();
5138 selection->add (new_selection);
5139 begin_selection_op_history();
5142 if (show_editor_mixer_when_tracks_arrive) {
5143 show_editor_mixer (true);
5146 editor_list_button.set_sensitive (true);
5150 Editor::timeaxisview_deleted (TimeAxisView *tv)
5152 if (tv == entered_track) {
5156 if (_session && _session->deletion_in_progress()) {
5157 /* the situation is under control */
5161 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5163 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5165 _routes->route_removed (tv);
5167 TimeAxisView::Children c = tv->get_child_list ();
5168 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5169 if (entered_track == i->get()) {
5174 /* remove it from the list of track views */
5176 TrackViewList::iterator i;
5178 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5179 i = track_views.erase (i);
5182 /* update whatever the current mixer strip is displaying, if revelant */
5184 boost::shared_ptr<Route> route;
5187 route = rtav->route ();
5190 if (current_mixer_strip && current_mixer_strip->route() == route) {
5192 TimeAxisView* next_tv;
5194 if (track_views.empty()) {
5196 } else if (i == track_views.end()) {
5197 next_tv = track_views.front();
5204 set_selected_mixer_strip (*next_tv);
5206 /* make the editor mixer strip go away setting the
5207 * button to inactive (which also unticks the menu option)
5210 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5216 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5218 if (apply_to_selection) {
5219 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5221 TrackSelection::iterator j = i;
5224 hide_track_in_display (*i, false);
5229 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5231 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5232 // this will hide the mixer strip
5233 set_selected_mixer_strip (*tv);
5236 _routes->hide_track_in_display (*tv);
5241 Editor::sync_track_view_list_and_routes ()
5243 track_views = TrackViewList (_routes->views ());
5245 _summary->set_background_dirty();
5246 _group_tabs->set_dirty ();
5248 return false; // do not call again (until needed)
5252 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5254 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5259 /** Find a RouteTimeAxisView by the ID of its route */
5261 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5263 RouteTimeAxisView* v;
5265 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5266 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5267 if(v->route()->id() == id) {
5277 Editor::fit_route_group (RouteGroup *g)
5279 TrackViewList ts = axis_views_from_routes (g->route_list ());
5284 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5286 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5289 _session->cancel_audition ();
5293 if (_session->is_auditioning()) {
5294 _session->cancel_audition ();
5295 if (r == last_audition_region) {
5300 _session->audition_region (r);
5301 last_audition_region = r;
5306 Editor::hide_a_region (boost::shared_ptr<Region> r)
5308 r->set_hidden (true);
5312 Editor::show_a_region (boost::shared_ptr<Region> r)
5314 r->set_hidden (false);
5318 Editor::audition_region_from_region_list ()
5320 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5324 Editor::hide_region_from_region_list ()
5326 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5330 Editor::show_region_in_region_list ()
5332 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5336 Editor::step_edit_status_change (bool yn)
5339 start_step_editing ();
5341 stop_step_editing ();
5346 Editor::start_step_editing ()
5348 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5352 Editor::stop_step_editing ()
5354 step_edit_connection.disconnect ();
5358 Editor::check_step_edit ()
5360 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5361 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5363 mtv->check_step_edit ();
5367 return true; // do it again, till we stop
5371 Editor::scroll_press (Direction dir)
5373 ++_scroll_callbacks;
5375 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5376 /* delay the first auto-repeat */
5382 scroll_backward (1);
5390 scroll_up_one_track ();
5394 scroll_down_one_track ();
5398 /* do hacky auto-repeat */
5399 if (!_scroll_connection.connected ()) {
5401 _scroll_connection = Glib::signal_timeout().connect (
5402 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5405 _scroll_callbacks = 0;
5412 Editor::scroll_release ()
5414 _scroll_connection.disconnect ();
5417 /** Queue a change for the Editor viewport x origin to follow the playhead */
5419 Editor::reset_x_origin_to_follow_playhead ()
5421 framepos_t const frame = playhead_cursor->current_frame ();
5423 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5425 if (_session->transport_speed() < 0) {
5427 if (frame > (current_page_samples() / 2)) {
5428 center_screen (frame-(current_page_samples()/2));
5430 center_screen (current_page_samples()/2);
5437 if (frame < leftmost_frame) {
5439 if (_session->transport_rolling()) {
5440 /* rolling; end up with the playhead at the right of the page */
5441 l = frame - current_page_samples ();
5443 /* not rolling: end up with the playhead 1/4 of the way along the page */
5444 l = frame - current_page_samples() / 4;
5448 if (_session->transport_rolling()) {
5449 /* rolling: end up with the playhead on the left of the page */
5452 /* not rolling: end up with the playhead 3/4 of the way along the page */
5453 l = frame - 3 * current_page_samples() / 4;
5461 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5467 Editor::super_rapid_screen_update ()
5469 if (!_session || !_session->engine().running()) {
5473 /* METERING / MIXER STRIPS */
5475 /* update track meters, if required */
5476 if (contents().is_mapped() && meters_running) {
5477 RouteTimeAxisView* rtv;
5478 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5479 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5480 rtv->fast_update ();
5485 /* and any current mixer strip */
5486 if (current_mixer_strip) {
5487 current_mixer_strip->fast_update ();
5490 /* PLAYHEAD AND VIEWPORT */
5492 framepos_t const frame = _session->audible_frame();
5494 /* There are a few reasons why we might not update the playhead / viewport stuff:
5496 * 1. we don't update things when there's a pending locate request, otherwise
5497 * when the editor requests a locate there is a chance that this method
5498 * will move the playhead before the locate request is processed, causing
5500 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5501 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5504 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5506 last_update_frame = frame;
5508 if (!_dragging_playhead) {
5509 playhead_cursor->set_position (frame);
5512 if (!_stationary_playhead) {
5514 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5515 /* We only do this if we aren't already
5516 handling a visual change (ie if
5517 pending_visual_change.being_handled is
5518 false) so that these requests don't stack
5519 up there are too many of them to handle in
5522 reset_x_origin_to_follow_playhead ();
5527 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5528 framepos_t const frame = playhead_cursor->current_frame ();
5529 double target = ((double)frame - (double)current_page_samples()/2.0);
5530 if (target <= 0.0) {
5533 // compare to EditorCursor::set_position()
5534 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5535 double const new_pos = sample_to_pixel_unrounded (target);
5536 if (rint (new_pos) != rint (old_pos)) {
5537 reset_x_origin (pixel_to_sample (floor (new_pos)));
5548 Editor::session_going_away ()
5550 _have_idled = false;
5552 _session_connections.drop_connections ();
5554 super_rapid_screen_update_connection.disconnect ();
5556 selection->clear ();
5557 cut_buffer->clear ();
5559 clicked_regionview = 0;
5560 clicked_axisview = 0;
5561 clicked_routeview = 0;
5562 entered_regionview = 0;
5564 last_update_frame = 0;
5567 playhead_cursor->hide ();
5569 /* rip everything out of the list displays */
5573 _route_groups->clear ();
5575 /* do this first so that deleting a track doesn't reset cms to null
5576 and thus cause a leak.
5579 if (current_mixer_strip) {
5580 if (current_mixer_strip->get_parent() != 0) {
5581 global_hpacker.remove (*current_mixer_strip);
5583 delete current_mixer_strip;
5584 current_mixer_strip = 0;
5587 /* delete all trackviews */
5589 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5592 track_views.clear ();
5594 nudge_clock->set_session (0);
5596 editor_list_button.set_active(false);
5597 editor_list_button.set_sensitive(false);
5599 /* clear tempo/meter rulers */
5600 remove_metric_marks ();
5602 clear_marker_display ();
5604 stop_step_editing ();
5608 /* get rid of any existing editor mixer strip */
5610 WindowTitle title(Glib::get_application_name());
5611 title += _("Editor");
5613 own_window()->set_title (title.get_string());
5616 SessionHandlePtr::session_going_away ();
5621 Editor::show_editor_list (bool yn)
5624 _the_notebook.show ();
5626 _the_notebook.hide ();
5631 Editor::change_region_layering_order (bool from_context_menu)
5633 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5635 if (!clicked_routeview) {
5636 if (layering_order_editor) {
5637 layering_order_editor->hide ();
5642 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5648 boost::shared_ptr<Playlist> pl = track->playlist();
5654 if (layering_order_editor == 0) {
5655 layering_order_editor = new RegionLayeringOrderEditor (*this);
5658 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5659 layering_order_editor->maybe_present ();
5663 Editor::update_region_layering_order_editor ()
5665 if (layering_order_editor && layering_order_editor->is_visible ()) {
5666 change_region_layering_order (true);
5671 Editor::setup_fade_images ()
5673 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5674 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5675 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5676 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5677 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5679 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5680 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5681 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5682 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5683 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5685 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5686 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5687 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5688 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5689 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5691 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5692 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5693 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5694 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5695 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5699 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5701 Editor::action_menu_item (std::string const & name)
5703 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5706 return *manage (a->create_menu_item ());
5710 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5712 EventBox* b = manage (new EventBox);
5713 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5714 Label* l = manage (new Label (name));
5718 _the_notebook.append_page (widget, *b);
5722 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5724 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5725 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5728 if (ev->type == GDK_2BUTTON_PRESS) {
5730 /* double-click on a notebook tab shrinks or expands the notebook */
5732 if (_notebook_shrunk) {
5733 if (pre_notebook_shrink_pane_width) {
5734 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5736 _notebook_shrunk = false;
5738 pre_notebook_shrink_pane_width = edit_pane.get_position();
5740 /* this expands the LHS of the edit pane to cover the notebook
5741 PAGE but leaves the tabs visible.
5743 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5744 _notebook_shrunk = true;
5752 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5754 using namespace Menu_Helpers;
5756 MenuList& items = _control_point_context_menu.items ();
5759 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5760 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5761 if (!can_remove_control_point (item)) {
5762 items.back().set_sensitive (false);
5765 _control_point_context_menu.popup (event->button.button, event->button.time);
5769 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5771 using namespace Menu_Helpers;
5773 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5778 /* We need to get the selection here and pass it to the operations, since
5779 popping up the menu will cause a region leave event which clears
5780 entered_regionview. */
5782 MidiRegionView& mrv = note->region_view();
5783 const RegionSelection rs = get_regions_from_selection_and_entered ();
5784 const uint32_t sel_size = mrv.selection_size ();
5786 MenuList& items = _note_context_menu.items();
5790 items.push_back(MenuElem(_("Delete"),
5791 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5794 items.push_back(MenuElem(_("Edit..."),
5795 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5796 if (sel_size != 1) {
5797 items.back().set_sensitive (false);
5800 items.push_back(MenuElem(_("Transpose..."),
5801 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
5804 items.push_back(MenuElem(_("Legatize"),
5805 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5807 items.back().set_sensitive (false);
5810 items.push_back(MenuElem(_("Quantize..."),
5811 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5813 items.push_back(MenuElem(_("Remove Overlap"),
5814 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5816 items.back().set_sensitive (false);
5819 items.push_back(MenuElem(_("Transform..."),
5820 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5822 _note_context_menu.popup (event->button.button, event->button.time);
5826 Editor::zoom_vertical_modifier_released()
5828 _stepping_axis_view = 0;
5832 Editor::ui_parameter_changed (string parameter)
5834 if (parameter == "icon-set") {
5835 while (!_cursor_stack.empty()) {
5836 _cursor_stack.pop_back();
5838 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
5839 _cursor_stack.push_back(_cursors->grabber);
5840 } else if (parameter == "draggable-playhead") {
5841 if (_verbose_cursor) {
5842 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
5848 Editor::use_own_window (bool and_fill_it)
5850 bool new_window = !own_window();
5852 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
5854 if (win && new_window) {
5855 win->set_name ("EditorWindow");
5857 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
5859 // win->signal_realize().connect (*this, &Editor::on_realize);
5860 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
5861 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
5862 win->set_data ("ardour-bindings", bindings);
5867 DisplaySuspender ds;
5868 contents().show_all ();
5870 /* XXX: this is a bit unfortunate; it would probably
5871 be nicer if we could just call show () above rather
5872 than needing the show_all ()
5875 /* re-hide stuff if necessary */
5876 editor_list_button_toggled ();
5877 parameter_changed ("show-summary");
5878 parameter_changed ("show-group-tabs");
5879 parameter_changed ("show-zoom-tools");
5881 /* now reset all audio_time_axis heights, because widgets might need
5887 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5888 tv = (static_cast<TimeAxisView*>(*i));
5889 tv->reset_height ();
5892 if (current_mixer_strip) {
5893 current_mixer_strip->hide_things ();
5894 current_mixer_strip->parameter_changed ("mixer-element-visibility");