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/utils.h"
63 #include "gtkmm2ext/window_title.h"
64 #include "gtkmm2ext/choice.h"
65 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
67 #include "ardour/audio_track.h"
68 #include "ardour/audioengine.h"
69 #include "ardour/audioregion.h"
70 #include "ardour/lmath.h"
71 #include "ardour/location.h"
72 #include "ardour/profile.h"
73 #include "ardour/route_group.h"
74 #include "ardour/session_playlists.h"
75 #include "ardour/tempo.h"
76 #include "ardour/utils.h"
78 #include "canvas/debug.h"
79 #include "canvas/text.h"
81 #include "control_protocol/control_protocol.h"
84 #include "analysis_window.h"
85 #include "audio_clock.h"
86 #include "audio_region_view.h"
87 #include "audio_streamview.h"
88 #include "audio_time_axis.h"
89 #include "automation_time_axis.h"
90 #include "bundle_manager.h"
91 #include "crossfade_edit.h"
95 #include "editor_cursors.h"
96 #include "editor_drag.h"
97 #include "editor_group_tabs.h"
98 #include "editor_locations.h"
99 #include "editor_regions.h"
100 #include "editor_route_groups.h"
101 #include "editor_routes.h"
102 #include "editor_snapshots.h"
103 #include "editor_summary.h"
104 #include "global_port_matrix.h"
105 #include "gui_object.h"
106 #include "gui_thread.h"
107 #include "keyboard.h"
109 #include "midi_region_view.h"
110 #include "midi_time_axis.h"
111 #include "mixer_strip.h"
112 #include "mixer_ui.h"
113 #include "mouse_cursors.h"
114 #include "note_base.h"
115 #include "playlist_selector.h"
116 #include "public_editor.h"
117 #include "quantize_dialog.h"
118 #include "region_layering_order_editor.h"
119 #include "rgb_macros.h"
120 #include "rhythm_ferret.h"
121 #include "selection.h"
123 #include "tempo_lines.h"
124 #include "time_axis_view.h"
126 #include "tooltips.h"
127 #include "ui_config.h"
129 #include "verbose_cursor.h"
134 using namespace ARDOUR;
135 using namespace ARDOUR_UI_UTILS;
138 using namespace Glib;
139 using namespace Gtkmm2ext;
140 using namespace Editing;
142 using PBD::internationalize;
144 using Gtkmm2ext::Keyboard;
146 double Editor::timebar_height = 15.0;
148 static const gchar *_snap_type_strings[] = {
182 static const gchar *_snap_mode_strings[] = {
189 static const gchar *_edit_point_strings[] = {
196 static const gchar *_edit_mode_strings[] = {
204 static const gchar *_zoom_focus_strings[] = {
214 #ifdef USE_RUBBERBAND
215 static const gchar *_rb_opt_strings[] = {
218 N_("Balanced multitimbral mixture"),
219 N_("Unpitched percussion with stable notes"),
220 N_("Crisp monophonic instrumental"),
221 N_("Unpitched solo percussion"),
222 N_("Resample without preserving pitch"),
227 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
230 pane_size_watcher (Paned* pane)
232 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
236 Quartz: impossible to access
238 so stop that by preventing it from ever getting too narrow. 35
239 pixels is basically a rough guess at the tab width.
244 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
246 gint pos = pane->get_position ();
248 if (pos > max_width_of_lhs) {
249 pane->set_position (max_width_of_lhs);
254 : PublicEditor (global_hpacker)
255 , editor_mixer_strip_width (Wide)
256 , constructed (false)
257 , _playlist_selector (0)
258 , no_save_visual (false)
260 , samples_per_pixel (2048)
261 , zoom_focus (ZoomFocusPlayhead)
262 , mouse_mode (MouseObject)
263 , pre_internal_snap_type (SnapToBeat)
264 , pre_internal_snap_mode (SnapOff)
265 , internal_snap_type (SnapToBeat)
266 , internal_snap_mode (SnapOff)
267 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
268 , _notebook_shrunk (false)
269 , location_marker_color (0)
270 , location_range_color (0)
271 , location_loop_color (0)
272 , location_punch_color (0)
273 , location_cd_marker_color (0)
275 , _show_marker_lines (false)
276 , clicked_axisview (0)
277 , clicked_routeview (0)
278 , clicked_regionview (0)
279 , clicked_selection (0)
280 , clicked_control_point (0)
281 , button_release_can_deselect (true)
282 , _mouse_changed_selection (false)
283 , region_edit_menu_split_item (0)
284 , region_edit_menu_split_multichannel_item (0)
285 , track_region_edit_playlist_menu (0)
286 , track_edit_playlist_submenu (0)
287 , track_selection_edit_playlist_submenu (0)
288 , _popup_region_menu_item (0)
290 , _track_canvas_viewport (0)
291 , within_track_canvas (false)
292 , _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)
465 /* we are a singleton */
467 PublicEditor::_instance = this;
471 last_event_time.tv_sec = 0;
472 last_event_time.tv_usec = 0;
474 selection_op_history.clear();
477 snap_type_strings = I18N (_snap_type_strings);
478 snap_mode_strings = I18N (_snap_mode_strings);
479 zoom_focus_strings = I18N (_zoom_focus_strings);
480 edit_mode_strings = I18N (_edit_mode_strings);
481 edit_point_strings = I18N (_edit_point_strings);
482 #ifdef USE_RUBBERBAND
483 rb_opt_strings = I18N (_rb_opt_strings);
487 build_edit_mode_menu();
488 build_zoom_focus_menu();
489 build_track_count_menu();
490 build_snap_mode_menu();
491 build_snap_type_menu();
492 build_edit_point_menu();
494 location_marker_color = ARDOUR_UI::config()->color ("location marker");
495 location_range_color = ARDOUR_UI::config()->color ("location range");
496 location_cd_marker_color = ARDOUR_UI::config()->color ("location cd marker");
497 location_loop_color = ARDOUR_UI::config()->color ("location loop");
498 location_punch_color = ARDOUR_UI::config()->color ("location punch");
500 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
502 TimeAxisView::setup_sizes ();
503 ArdourMarker::setup_sizes (timebar_height);
505 bbt_label.set_name ("EditorRulerLabel");
506 bbt_label.set_size_request (-1, (int)timebar_height);
507 bbt_label.set_alignment (1.0, 0.5);
508 bbt_label.set_padding (5,0);
510 bbt_label.set_no_show_all();
511 minsec_label.set_name ("EditorRulerLabel");
512 minsec_label.set_size_request (-1, (int)timebar_height);
513 minsec_label.set_alignment (1.0, 0.5);
514 minsec_label.set_padding (5,0);
515 minsec_label.hide ();
516 minsec_label.set_no_show_all();
517 timecode_label.set_name ("EditorRulerLabel");
518 timecode_label.set_size_request (-1, (int)timebar_height);
519 timecode_label.set_alignment (1.0, 0.5);
520 timecode_label.set_padding (5,0);
521 timecode_label.hide ();
522 timecode_label.set_no_show_all();
523 samples_label.set_name ("EditorRulerLabel");
524 samples_label.set_size_request (-1, (int)timebar_height);
525 samples_label.set_alignment (1.0, 0.5);
526 samples_label.set_padding (5,0);
527 samples_label.hide ();
528 samples_label.set_no_show_all();
530 tempo_label.set_name ("EditorRulerLabel");
531 tempo_label.set_size_request (-1, (int)timebar_height);
532 tempo_label.set_alignment (1.0, 0.5);
533 tempo_label.set_padding (5,0);
535 tempo_label.set_no_show_all();
537 meter_label.set_name ("EditorRulerLabel");
538 meter_label.set_size_request (-1, (int)timebar_height);
539 meter_label.set_alignment (1.0, 0.5);
540 meter_label.set_padding (5,0);
542 meter_label.set_no_show_all();
544 if (Profile->get_trx()) {
545 mark_label.set_text (_("Markers"));
547 mark_label.set_name ("EditorRulerLabel");
548 mark_label.set_size_request (-1, (int)timebar_height);
549 mark_label.set_alignment (1.0, 0.5);
550 mark_label.set_padding (5,0);
552 mark_label.set_no_show_all();
554 cd_mark_label.set_name ("EditorRulerLabel");
555 cd_mark_label.set_size_request (-1, (int)timebar_height);
556 cd_mark_label.set_alignment (1.0, 0.5);
557 cd_mark_label.set_padding (5,0);
558 cd_mark_label.hide();
559 cd_mark_label.set_no_show_all();
561 videotl_bar_height = 4;
562 videotl_label.set_name ("EditorRulerLabel");
563 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
564 videotl_label.set_alignment (1.0, 0.5);
565 videotl_label.set_padding (5,0);
566 videotl_label.hide();
567 videotl_label.set_no_show_all();
569 range_mark_label.set_name ("EditorRulerLabel");
570 range_mark_label.set_size_request (-1, (int)timebar_height);
571 range_mark_label.set_alignment (1.0, 0.5);
572 range_mark_label.set_padding (5,0);
573 range_mark_label.hide();
574 range_mark_label.set_no_show_all();
576 transport_mark_label.set_name ("EditorRulerLabel");
577 transport_mark_label.set_size_request (-1, (int)timebar_height);
578 transport_mark_label.set_alignment (1.0, 0.5);
579 transport_mark_label.set_padding (5,0);
580 transport_mark_label.hide();
581 transport_mark_label.set_no_show_all();
583 initialize_canvas ();
585 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
587 _summary = new EditorSummary (this);
589 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
590 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
592 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
594 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
595 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
597 edit_controls_vbox.set_spacing (0);
598 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
599 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
601 HBox* h = manage (new HBox);
602 _group_tabs = new EditorGroupTabs (this);
603 if (!ARDOUR::Profile->get_trx()) {
604 h->pack_start (*_group_tabs, PACK_SHRINK);
606 h->pack_start (edit_controls_vbox);
607 controls_layout.add (*h);
609 controls_layout.set_name ("EditControlsBase");
610 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
611 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
612 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
614 _cursors = new MouseCursors;
615 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
616 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
618 /* Push default cursor to ever-present bottom of cursor stack. */
619 push_canvas_cursor(_cursors->grabber);
621 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
623 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
624 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
625 pad_line_1->set_outline_color (0xFF0000FF);
631 edit_packer.set_col_spacings (0);
632 edit_packer.set_row_spacings (0);
633 edit_packer.set_homogeneous (false);
634 edit_packer.set_border_width (0);
635 edit_packer.set_name ("EditorWindow");
637 time_bars_event_box.add (time_bars_vbox);
638 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
639 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
641 /* labels for the time bars */
642 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
644 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
646 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
648 bottom_hbox.set_border_width (2);
649 bottom_hbox.set_spacing (3);
651 _route_groups = new EditorRouteGroups (this);
652 _routes = new EditorRoutes (this);
653 _regions = new EditorRegions (this);
654 _snapshots = new EditorSnapshots (this);
655 _locations = new EditorLocations (this);
657 /* these are static location signals */
659 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
660 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
661 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
663 add_notebook_page (_("Regions"), _regions->widget ());
664 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
665 add_notebook_page (_("Snapshots"), _snapshots->widget ());
666 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
667 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
669 _the_notebook.set_show_tabs (true);
670 _the_notebook.set_scrollable (true);
671 _the_notebook.popup_disable ();
672 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
673 _the_notebook.show_all ();
675 _notebook_shrunk = false;
677 editor_summary_pane.pack1(edit_packer);
679 Button* summary_arrows_left_left = manage (new Button);
680 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
681 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
682 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
684 Button* summary_arrows_left_right = manage (new Button);
685 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
686 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
687 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
689 VBox* summary_arrows_left = manage (new VBox);
690 summary_arrows_left->pack_start (*summary_arrows_left_left);
691 summary_arrows_left->pack_start (*summary_arrows_left_right);
693 Button* summary_arrows_right_up = manage (new Button);
694 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
695 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
696 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
698 Button* summary_arrows_right_down = manage (new Button);
699 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
700 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
701 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
703 VBox* summary_arrows_right = manage (new VBox);
704 summary_arrows_right->pack_start (*summary_arrows_right_up);
705 summary_arrows_right->pack_start (*summary_arrows_right_down);
707 Frame* summary_frame = manage (new Frame);
708 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
710 summary_frame->add (*_summary);
711 summary_frame->show ();
713 _summary_hbox.pack_start (*summary_arrows_left, false, false);
714 _summary_hbox.pack_start (*summary_frame, true, true);
715 _summary_hbox.pack_start (*summary_arrows_right, false, false);
717 if (!ARDOUR::Profile->get_trx()) {
718 editor_summary_pane.pack2 (_summary_hbox);
721 edit_pane.pack1 (editor_summary_pane, true, true);
722 if (!ARDOUR::Profile->get_trx()) {
723 edit_pane.pack2 (_the_notebook, false, true);
726 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
728 /* XXX: editor_summary_pane might need similar to the edit_pane */
730 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
732 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
733 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
735 top_hbox.pack_start (toolbar_frame);
737 HBox *hbox = manage (new HBox);
738 hbox->pack_start (edit_pane, true, true);
740 global_vpacker.pack_start (top_hbox, false, false);
741 global_vpacker.pack_start (*hbox, true, true);
742 global_hpacker.pack_start (global_vpacker, true, true);
744 /* need to show the "contents" widget so that notebook will show if tab is switched to
747 global_hpacker.show ();
749 /* register actions now so that set_state() can find them and set toggles/checks etc */
756 _playlist_selector = new PlaylistSelector();
757 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
759 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
763 nudge_forward_button.set_name ("nudge button");
764 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
766 nudge_backward_button.set_name ("nudge button");
767 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
769 fade_context_menu.set_name ("ArdourContextMenu");
771 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
773 /* allow external control surfaces/protocols to do various things */
775 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
776 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
777 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
778 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
779 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
780 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
781 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
782 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
783 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
784 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
785 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
786 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
787 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
788 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
790 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
791 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
792 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
793 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
794 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
796 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
798 /* problematic: has to return a value and thus cannot be x-thread */
800 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
802 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
803 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
805 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
807 _ignore_region_action = false;
808 _last_region_menu_was_main = false;
809 _popup_region_menu_item = 0;
811 _ignore_follow_edits = false;
813 _show_marker_lines = false;
815 /* Button bindings */
817 button_bindings = new Bindings ("editor-mouse");
819 XMLNode* node = button_settings();
821 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
822 button_bindings->load_operation (**i);
828 /* grab current parameter state */
829 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
830 UIConfiguration::instance().map_parameters (pc);
832 setup_fade_images ();
839 delete button_bindings;
841 delete _route_groups;
842 delete _track_canvas_viewport;
845 delete quantize_dialog;
851 delete _playlist_selector;
853 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
859 Editor::button_settings () const
861 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
862 XMLNode* node = find_named_node (*settings, X_("Buttons"));
865 node = new XMLNode (X_("Buttons"));
872 Editor::get_smart_mode () const
874 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
878 Editor::catch_vanishing_regionview (RegionView *rv)
880 /* note: the selection will take care of the vanishing
881 audioregionview by itself.
884 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
888 if (clicked_regionview == rv) {
889 clicked_regionview = 0;
892 if (entered_regionview == rv) {
893 set_entered_regionview (0);
896 if (!_all_region_actions_sensitized) {
897 sensitize_all_region_actions (true);
902 Editor::set_entered_regionview (RegionView* rv)
904 if (rv == entered_regionview) {
908 if (entered_regionview) {
909 entered_regionview->exited ();
912 entered_regionview = rv;
914 if (entered_regionview != 0) {
915 entered_regionview->entered ();
918 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
919 /* This RegionView entry might have changed what region actions
920 are allowed, so sensitize them all in case a key is pressed.
922 sensitize_all_region_actions (true);
927 Editor::set_entered_track (TimeAxisView* tav)
930 entered_track->exited ();
936 entered_track->entered ();
941 Editor::instant_save ()
943 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
948 _session->add_instant_xml(get_state());
950 Config->add_instant_xml(get_state());
955 Editor::control_vertical_zoom_in_all ()
957 tav_zoom_smooth (false, true);
961 Editor::control_vertical_zoom_out_all ()
963 tav_zoom_smooth (true, true);
967 Editor::control_vertical_zoom_in_selected ()
969 tav_zoom_smooth (false, false);
973 Editor::control_vertical_zoom_out_selected ()
975 tav_zoom_smooth (true, false);
979 Editor::control_view (uint32_t view)
981 goto_visual_state (view);
985 Editor::control_unselect ()
987 selection->clear_tracks ();
991 Editor::control_select (uint32_t rid, Selection::Operation op)
993 /* handles the (static) signal from the ControlProtocol class that
994 * requests setting the selected track to a given RID
1001 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1007 TimeAxisView* tav = axis_view_from_route (r);
1011 case Selection::Add:
1012 selection->add (tav);
1014 case Selection::Toggle:
1015 selection->toggle (tav);
1017 case Selection::Extend:
1019 case Selection::Set:
1020 selection->set (tav);
1024 selection->clear_tracks ();
1029 Editor::control_step_tracks_up ()
1031 scroll_tracks_up_line ();
1035 Editor::control_step_tracks_down ()
1037 scroll_tracks_down_line ();
1041 Editor::control_scroll (float fraction)
1043 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1049 double step = fraction * current_page_samples();
1052 _control_scroll_target is an optional<T>
1054 it acts like a pointer to an framepos_t, with
1055 a operator conversion to boolean to check
1056 that it has a value could possibly use
1057 playhead_cursor->current_frame to store the
1058 value and a boolean in the class to know
1059 when it's out of date
1062 if (!_control_scroll_target) {
1063 _control_scroll_target = _session->transport_frame();
1064 _dragging_playhead = true;
1067 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1068 *_control_scroll_target = 0;
1069 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1070 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1072 *_control_scroll_target += (framepos_t) trunc (step);
1075 /* move visuals, we'll catch up with it later */
1077 playhead_cursor->set_position (*_control_scroll_target);
1078 UpdateAllTransportClocks (*_control_scroll_target);
1080 if (*_control_scroll_target > (current_page_samples() / 2)) {
1081 /* try to center PH in window */
1082 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1088 Now we do a timeout to actually bring the session to the right place
1089 according to the playhead. This is to avoid reading disk buffers on every
1090 call to control_scroll, which is driven by ScrollTimeline and therefore
1091 probably by a control surface wheel which can generate lots of events.
1093 /* cancel the existing timeout */
1095 control_scroll_connection.disconnect ();
1097 /* add the next timeout */
1099 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1103 Editor::deferred_control_scroll (framepos_t /*target*/)
1105 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1106 // reset for next stream
1107 _control_scroll_target = boost::none;
1108 _dragging_playhead = false;
1113 Editor::access_action (std::string action_group, std::string action_item)
1119 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1122 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1130 Editor::on_realize ()
1134 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1135 start_lock_event_timing ();
1140 Editor::start_lock_event_timing ()
1142 /* check if we should lock the GUI every 30 seconds */
1144 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1148 Editor::generic_event_handler (GdkEvent* ev)
1151 case GDK_BUTTON_PRESS:
1152 case GDK_BUTTON_RELEASE:
1153 case GDK_MOTION_NOTIFY:
1155 case GDK_KEY_RELEASE:
1156 if (contents().is_mapped()) {
1157 gettimeofday (&last_event_time, 0);
1161 case GDK_LEAVE_NOTIFY:
1162 switch (ev->crossing.detail) {
1163 case GDK_NOTIFY_UNKNOWN:
1164 case GDK_NOTIFY_INFERIOR:
1165 case GDK_NOTIFY_ANCESTOR:
1167 case GDK_NOTIFY_VIRTUAL:
1168 case GDK_NOTIFY_NONLINEAR:
1169 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1170 /* leaving window, so reset focus, thus ending any and
1171 all text entry operations.
1186 Editor::lock_timeout_callback ()
1188 struct timeval now, delta;
1190 gettimeofday (&now, 0);
1192 timersub (&now, &last_event_time, &delta);
1194 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1196 /* don't call again. Returning false will effectively
1197 disconnect us from the timer callback.
1199 unlock() will call start_lock_event_timing() to get things
1209 Editor::map_position_change (framepos_t frame)
1211 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1213 if (_session == 0) {
1217 if (_follow_playhead) {
1218 center_screen (frame);
1221 playhead_cursor->set_position (frame);
1225 Editor::center_screen (framepos_t frame)
1227 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1229 /* if we're off the page, then scroll.
1232 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1233 center_screen_internal (frame, page);
1238 Editor::center_screen_internal (framepos_t frame, float page)
1243 frame -= (framepos_t) page;
1248 reset_x_origin (frame);
1253 Editor::update_title ()
1255 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1257 if (!own_window()) {
1262 bool dirty = _session->dirty();
1264 string session_name;
1266 if (_session->snap_name() != _session->name()) {
1267 session_name = _session->snap_name();
1269 session_name = _session->name();
1273 session_name = "*" + session_name;
1276 WindowTitle title(session_name);
1277 title += Glib::get_application_name();
1278 own_window()->set_title (title.get_string());
1280 /* ::session_going_away() will have taken care of it */
1285 Editor::set_session (Session *t)
1287 SessionHandlePtr::set_session (t);
1293 _playlist_selector->set_session (_session);
1294 nudge_clock->set_session (_session);
1295 _summary->set_session (_session);
1296 _group_tabs->set_session (_session);
1297 _route_groups->set_session (_session);
1298 _regions->set_session (_session);
1299 _snapshots->set_session (_session);
1300 _routes->set_session (_session);
1301 _locations->set_session (_session);
1303 if (rhythm_ferret) {
1304 rhythm_ferret->set_session (_session);
1307 if (analysis_window) {
1308 analysis_window->set_session (_session);
1312 sfbrowser->set_session (_session);
1315 compute_fixed_ruler_scale ();
1317 /* Make sure we have auto loop and auto punch ranges */
1319 Location* loc = _session->locations()->auto_loop_location();
1321 loc->set_name (_("Loop"));
1324 loc = _session->locations()->auto_punch_location();
1327 loc->set_name (_("Punch"));
1330 refresh_location_display ();
1332 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1333 the selected Marker; this needs the LocationMarker list to be available.
1335 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1336 set_state (*node, Stateful::loading_state_version);
1338 /* catch up with the playhead */
1340 _session->request_locate (playhead_cursor->current_frame ());
1341 _pending_initial_locate = true;
1345 /* These signals can all be emitted by a non-GUI thread. Therefore the
1346 handlers for them must not attempt to directly interact with the GUI,
1347 but use PBD::Signal<T>::connect() which accepts an event loop
1348 ("context") where the handler will be asked to run.
1351 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1352 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1353 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1354 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1355 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1356 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1357 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1358 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1359 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1360 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1361 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1362 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1363 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1365 playhead_cursor->show ();
1367 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1368 Config->map_parameters (pc);
1369 _session->config.map_parameters (pc);
1371 restore_ruler_visibility ();
1372 //tempo_map_changed (PropertyChange (0));
1373 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1375 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1376 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1379 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1380 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1383 switch (_snap_type) {
1384 case SnapToRegionStart:
1385 case SnapToRegionEnd:
1386 case SnapToRegionSync:
1387 case SnapToRegionBoundary:
1388 build_region_boundary_cache ();
1395 /* register for undo history */
1396 _session->register_with_memento_command_factory(id(), this);
1397 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1399 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1401 start_updating_meters ();
1405 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1407 if (a->get_name() == "RegionMenu") {
1408 /* When the main menu's region menu is opened, we setup the actions so that they look right
1409 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1410 so we resensitize all region actions when the entered regionview or the region selection
1411 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1412 happens after the region context menu is opened. So we set a flag here, too.
1416 sensitize_the_right_region_actions ();
1417 _last_region_menu_was_main = true;
1422 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1424 using namespace Menu_Helpers;
1426 void (Editor::*emf)(FadeShape);
1427 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1430 images = &_xfade_in_images;
1431 emf = &Editor::set_fade_in_shape;
1433 images = &_xfade_out_images;
1434 emf = &Editor::set_fade_out_shape;
1439 _("Linear (for highly correlated material)"),
1440 *(*images)[FadeLinear],
1441 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1445 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1449 _("Constant power"),
1450 *(*images)[FadeConstantPower],
1451 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1454 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1459 *(*images)[FadeSymmetric],
1460 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1464 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1469 *(*images)[FadeSlow],
1470 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1473 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1478 *(*images)[FadeFast],
1479 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1482 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1485 /** Pop up a context menu for when the user clicks on a start crossfade */
1487 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1489 using namespace Menu_Helpers;
1490 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1495 MenuList& items (xfade_in_context_menu.items());
1498 if (arv->audio_region()->fade_in_active()) {
1499 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1501 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1504 items.push_back (SeparatorElem());
1505 fill_xfade_menu (items, true);
1507 xfade_in_context_menu.popup (button, time);
1510 /** Pop up a context menu for when the user clicks on an end crossfade */
1512 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1514 using namespace Menu_Helpers;
1515 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1520 MenuList& items (xfade_out_context_menu.items());
1523 if (arv->audio_region()->fade_out_active()) {
1524 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1526 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1529 items.push_back (SeparatorElem());
1530 fill_xfade_menu (items, false);
1532 xfade_out_context_menu.popup (button, time);
1536 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1538 using namespace Menu_Helpers;
1539 Menu* (Editor::*build_menu_function)();
1542 switch (item_type) {
1544 case RegionViewName:
1545 case RegionViewNameHighlight:
1546 case LeftFrameHandle:
1547 case RightFrameHandle:
1548 if (with_selection) {
1549 build_menu_function = &Editor::build_track_selection_context_menu;
1551 build_menu_function = &Editor::build_track_region_context_menu;
1556 if (with_selection) {
1557 build_menu_function = &Editor::build_track_selection_context_menu;
1559 build_menu_function = &Editor::build_track_context_menu;
1564 if (clicked_routeview->track()) {
1565 build_menu_function = &Editor::build_track_context_menu;
1567 build_menu_function = &Editor::build_track_bus_context_menu;
1572 /* probably shouldn't happen but if it does, we don't care */
1576 menu = (this->*build_menu_function)();
1577 menu->set_name ("ArdourContextMenu");
1579 /* now handle specific situations */
1581 switch (item_type) {
1583 case RegionViewName:
1584 case RegionViewNameHighlight:
1585 case LeftFrameHandle:
1586 case RightFrameHandle:
1587 if (!with_selection) {
1588 if (region_edit_menu_split_item) {
1589 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1590 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1592 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1595 if (region_edit_menu_split_multichannel_item) {
1596 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1597 region_edit_menu_split_multichannel_item->set_sensitive (true);
1599 region_edit_menu_split_multichannel_item->set_sensitive (false);
1612 /* probably shouldn't happen but if it does, we don't care */
1616 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1618 /* Bounce to disk */
1620 using namespace Menu_Helpers;
1621 MenuList& edit_items = menu->items();
1623 edit_items.push_back (SeparatorElem());
1625 switch (clicked_routeview->audio_track()->freeze_state()) {
1626 case AudioTrack::NoFreeze:
1627 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1630 case AudioTrack::Frozen:
1631 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1634 case AudioTrack::UnFrozen:
1635 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1641 if (item_type == StreamItem && clicked_routeview) {
1642 clicked_routeview->build_underlay_menu(menu);
1645 /* When the region menu is opened, we setup the actions so that they look right
1648 sensitize_the_right_region_actions ();
1649 _last_region_menu_was_main = false;
1651 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1652 menu->popup (button, time);
1656 Editor::build_track_context_menu ()
1658 using namespace Menu_Helpers;
1660 MenuList& edit_items = track_context_menu.items();
1663 add_dstream_context_items (edit_items);
1664 return &track_context_menu;
1668 Editor::build_track_bus_context_menu ()
1670 using namespace Menu_Helpers;
1672 MenuList& edit_items = track_context_menu.items();
1675 add_bus_context_items (edit_items);
1676 return &track_context_menu;
1680 Editor::build_track_region_context_menu ()
1682 using namespace Menu_Helpers;
1683 MenuList& edit_items = track_region_context_menu.items();
1686 /* we've just cleared the track region context menu, so the menu that these
1687 two items were on will have disappeared; stop them dangling.
1689 region_edit_menu_split_item = 0;
1690 region_edit_menu_split_multichannel_item = 0;
1692 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1695 boost::shared_ptr<Track> tr;
1696 boost::shared_ptr<Playlist> pl;
1698 if ((tr = rtv->track())) {
1699 add_region_context_items (edit_items, tr);
1703 add_dstream_context_items (edit_items);
1705 return &track_region_context_menu;
1709 Editor::analyze_region_selection ()
1711 if (analysis_window == 0) {
1712 analysis_window = new AnalysisWindow();
1715 analysis_window->set_session(_session);
1717 analysis_window->show_all();
1720 analysis_window->set_regionmode();
1721 analysis_window->analyze();
1723 analysis_window->present();
1727 Editor::analyze_range_selection()
1729 if (analysis_window == 0) {
1730 analysis_window = new AnalysisWindow();
1733 analysis_window->set_session(_session);
1735 analysis_window->show_all();
1738 analysis_window->set_rangemode();
1739 analysis_window->analyze();
1741 analysis_window->present();
1745 Editor::build_track_selection_context_menu ()
1747 using namespace Menu_Helpers;
1748 MenuList& edit_items = track_selection_context_menu.items();
1749 edit_items.clear ();
1751 add_selection_context_items (edit_items);
1752 // edit_items.push_back (SeparatorElem());
1753 // add_dstream_context_items (edit_items);
1755 return &track_selection_context_menu;
1759 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1761 using namespace Menu_Helpers;
1763 /* OK, stick the region submenu at the top of the list, and then add
1767 RegionSelection rs = get_regions_from_selection_and_entered ();
1769 string::size_type pos = 0;
1770 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1772 /* we have to hack up the region name because "_" has a special
1773 meaning for menu titles.
1776 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1777 menu_item_name.replace (pos, 1, "__");
1781 if (_popup_region_menu_item == 0) {
1782 _popup_region_menu_item = new MenuItem (menu_item_name);
1783 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1784 _popup_region_menu_item->show ();
1786 _popup_region_menu_item->set_label (menu_item_name);
1789 /* No latering allowed in later is higher layering model */
1790 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1791 if (act && Config->get_layer_model() == LaterHigher) {
1792 act->set_sensitive (false);
1794 act->set_sensitive (true);
1797 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1799 edit_items.push_back (*_popup_region_menu_item);
1800 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1801 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1803 edit_items.push_back (SeparatorElem());
1806 /** Add context menu items relevant to selection ranges.
1807 * @param edit_items List to add the items to.
1810 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1812 using namespace Menu_Helpers;
1814 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1815 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1817 edit_items.push_back (SeparatorElem());
1818 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1820 edit_items.push_back (SeparatorElem());
1821 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1823 edit_items.push_back (SeparatorElem());
1825 edit_items.push_back (
1827 _("Move Range Start to Previous Region Boundary"),
1828 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1832 edit_items.push_back (
1834 _("Move Range Start to Next Region Boundary"),
1835 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1839 edit_items.push_back (
1841 _("Move Range End to Previous Region Boundary"),
1842 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1846 edit_items.push_back (
1848 _("Move Range End to Next Region Boundary"),
1849 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1853 edit_items.push_back (SeparatorElem());
1854 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1855 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1857 edit_items.push_back (SeparatorElem());
1858 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1860 edit_items.push_back (SeparatorElem());
1861 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1862 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1863 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1865 edit_items.push_back (SeparatorElem());
1866 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1868 edit_items.push_back (SeparatorElem());
1869 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1870 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1872 edit_items.push_back (SeparatorElem());
1873 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1874 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1875 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1876 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1877 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1878 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1879 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1885 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1887 using namespace Menu_Helpers;
1891 Menu *play_menu = manage (new Menu);
1892 MenuList& play_items = play_menu->items();
1893 play_menu->set_name ("ArdourContextMenu");
1895 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1896 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1897 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1898 play_items.push_back (SeparatorElem());
1899 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1901 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1905 Menu *select_menu = manage (new Menu);
1906 MenuList& select_items = select_menu->items();
1907 select_menu->set_name ("ArdourContextMenu");
1909 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1910 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1911 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1912 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1913 select_items.push_back (SeparatorElem());
1914 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1915 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1916 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
1917 select_items.push_back (SeparatorElem());
1918 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
1919 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
1920 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1921 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1922 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1923 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1924 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1926 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1930 Menu *cutnpaste_menu = manage (new Menu);
1931 MenuList& cutnpaste_items = cutnpaste_menu->items();
1932 cutnpaste_menu->set_name ("ArdourContextMenu");
1934 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1935 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1936 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1938 cutnpaste_items.push_back (SeparatorElem());
1940 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1941 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1943 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1945 /* Adding new material */
1947 edit_items.push_back (SeparatorElem());
1948 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1949 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1953 Menu *nudge_menu = manage (new Menu());
1954 MenuList& nudge_items = nudge_menu->items();
1955 nudge_menu->set_name ("ArdourContextMenu");
1957 edit_items.push_back (SeparatorElem());
1958 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1959 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1960 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1961 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1963 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1967 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1969 using namespace Menu_Helpers;
1973 Menu *play_menu = manage (new Menu);
1974 MenuList& play_items = play_menu->items();
1975 play_menu->set_name ("ArdourContextMenu");
1977 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1978 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1979 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1983 Menu *select_menu = manage (new Menu);
1984 MenuList& select_items = select_menu->items();
1985 select_menu->set_name ("ArdourContextMenu");
1987 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1988 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1989 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1990 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1991 select_items.push_back (SeparatorElem());
1992 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
1993 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
1994 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1995 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1997 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2001 Menu *cutnpaste_menu = manage (new Menu);
2002 MenuList& cutnpaste_items = cutnpaste_menu->items();
2003 cutnpaste_menu->set_name ("ArdourContextMenu");
2005 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2006 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2007 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2009 Menu *nudge_menu = manage (new Menu());
2010 MenuList& nudge_items = nudge_menu->items();
2011 nudge_menu->set_name ("ArdourContextMenu");
2013 edit_items.push_back (SeparatorElem());
2014 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2015 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2016 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2017 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2019 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2023 Editor::snap_type() const
2029 Editor::snap_mode() const
2035 Editor::set_snap_to (SnapType st)
2037 unsigned int snap_ind = (unsigned int)st;
2039 if (internal_editing()) {
2040 internal_snap_type = st;
2042 pre_internal_snap_type = st;
2047 if (snap_ind > snap_type_strings.size() - 1) {
2049 _snap_type = (SnapType)snap_ind;
2052 string str = snap_type_strings[snap_ind];
2054 if (str != snap_type_selector.get_text()) {
2055 snap_type_selector.set_text (str);
2060 switch (_snap_type) {
2061 case SnapToBeatDiv128:
2062 case SnapToBeatDiv64:
2063 case SnapToBeatDiv32:
2064 case SnapToBeatDiv28:
2065 case SnapToBeatDiv24:
2066 case SnapToBeatDiv20:
2067 case SnapToBeatDiv16:
2068 case SnapToBeatDiv14:
2069 case SnapToBeatDiv12:
2070 case SnapToBeatDiv10:
2071 case SnapToBeatDiv8:
2072 case SnapToBeatDiv7:
2073 case SnapToBeatDiv6:
2074 case SnapToBeatDiv5:
2075 case SnapToBeatDiv4:
2076 case SnapToBeatDiv3:
2077 case SnapToBeatDiv2: {
2078 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2079 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2081 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2082 current_bbt_points_begin, current_bbt_points_end);
2083 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2084 current_bbt_points_begin, current_bbt_points_end);
2085 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2089 case SnapToRegionStart:
2090 case SnapToRegionEnd:
2091 case SnapToRegionSync:
2092 case SnapToRegionBoundary:
2093 build_region_boundary_cache ();
2101 redisplay_tempo (false);
2103 SnapChanged (); /* EMIT SIGNAL */
2107 Editor::set_snap_mode (SnapMode mode)
2109 string str = snap_mode_strings[(int)mode];
2111 if (internal_editing()) {
2112 internal_snap_mode = mode;
2114 pre_internal_snap_mode = mode;
2119 if (str != snap_mode_selector.get_text ()) {
2120 snap_mode_selector.set_text (str);
2127 Editor::set_edit_point_preference (EditPoint ep, bool force)
2129 bool changed = (_edit_point != ep);
2132 if (Profile->get_mixbus())
2133 if (ep == EditAtSelectedMarker)
2134 ep = EditAtPlayhead;
2136 string str = edit_point_strings[(int)ep];
2137 if (str != edit_point_selector.get_text ()) {
2138 edit_point_selector.set_text (str);
2141 update_all_enter_cursors();
2143 if (!force && !changed) {
2147 const char* action=NULL;
2149 switch (_edit_point) {
2150 case EditAtPlayhead:
2151 action = "edit-at-playhead";
2153 case EditAtSelectedMarker:
2154 action = "edit-at-marker";
2157 action = "edit-at-mouse";
2161 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2163 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2167 bool in_track_canvas;
2169 if (!mouse_frame (foo, in_track_canvas)) {
2170 in_track_canvas = false;
2173 reset_canvas_action_sensitivity (in_track_canvas);
2179 Editor::set_state (const XMLNode& node, int version)
2181 const XMLProperty* prop;
2184 Tabbable::set_state (node, version);
2186 if (_session && (prop = node.property ("playhead"))) {
2188 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2190 playhead_cursor->set_position (pos);
2192 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2193 playhead_cursor->set_position (0);
2196 playhead_cursor->set_position (0);
2199 if ((prop = node.property ("mixer-width"))) {
2200 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2203 if ((prop = node.property ("zoom-focus"))) {
2204 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2207 if ((prop = node.property ("zoom"))) {
2208 /* older versions of ardour used floating point samples_per_pixel */
2209 double f = PBD::atof (prop->value());
2210 reset_zoom (llrintf (f));
2212 reset_zoom (samples_per_pixel);
2215 if ((prop = node.property ("visible-track-count"))) {
2216 set_visible_track_count (PBD::atoi (prop->value()));
2219 if ((prop = node.property ("snap-to"))) {
2220 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2223 if ((prop = node.property ("snap-mode"))) {
2224 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2227 if ((prop = node.property ("internal-snap-to"))) {
2228 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2231 if ((prop = node.property ("internal-snap-mode"))) {
2232 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2235 if ((prop = node.property ("pre-internal-snap-to"))) {
2236 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2239 if ((prop = node.property ("pre-internal-snap-mode"))) {
2240 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2243 if ((prop = node.property ("mouse-mode"))) {
2244 MouseMode m = str2mousemode(prop->value());
2245 set_mouse_mode (m, true);
2247 set_mouse_mode (MouseObject, true);
2250 if ((prop = node.property ("left-frame")) != 0) {
2252 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2256 reset_x_origin (pos);
2260 if ((prop = node.property ("y-origin")) != 0) {
2261 reset_y_origin (atof (prop->value ()));
2264 if ((prop = node.property ("join-object-range"))) {
2265 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2266 bool yn = string_is_affirmative (prop->value());
2268 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2269 tact->set_active (!yn);
2270 tact->set_active (yn);
2272 set_mouse_mode(mouse_mode, true);
2275 if ((prop = node.property ("edit-point"))) {
2276 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2279 if ((prop = node.property ("show-measures"))) {
2280 bool yn = string_is_affirmative (prop->value());
2281 _show_measures = yn;
2284 if ((prop = node.property ("follow-playhead"))) {
2285 bool yn = string_is_affirmative (prop->value());
2286 set_follow_playhead (yn);
2289 if ((prop = node.property ("stationary-playhead"))) {
2290 bool yn = string_is_affirmative (prop->value());
2291 set_stationary_playhead (yn);
2294 if ((prop = node.property ("region-list-sort-type"))) {
2295 RegionListSortType st;
2296 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2299 if ((prop = node.property ("show-editor-mixer"))) {
2301 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2304 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2305 bool yn = string_is_affirmative (prop->value());
2307 /* do it twice to force the change */
2309 tact->set_active (!yn);
2310 tact->set_active (yn);
2313 if ((prop = node.property ("show-editor-list"))) {
2315 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2318 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2319 bool yn = string_is_affirmative (prop->value());
2321 /* do it twice to force the change */
2323 tact->set_active (!yn);
2324 tact->set_active (yn);
2327 if ((prop = node.property (X_("editor-list-page")))) {
2328 _the_notebook.set_current_page (atoi (prop->value ()));
2331 if ((prop = node.property (X_("show-marker-lines")))) {
2332 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2334 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2335 bool yn = string_is_affirmative (prop->value ());
2337 tact->set_active (!yn);
2338 tact->set_active (yn);
2341 XMLNodeList children = node.children ();
2342 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2343 selection->set_state (**i, Stateful::current_state_version);
2344 _regions->set_state (**i);
2347 if ((prop = node.property ("maximised"))) {
2348 bool yn = string_is_affirmative (prop->value());
2349 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2351 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2352 bool fs = tact && tact->get_active();
2354 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2358 if ((prop = node.property ("nudge-clock-value"))) {
2360 sscanf (prop->value().c_str(), "%" PRId64, &f);
2361 nudge_clock->set (f);
2363 nudge_clock->set_mode (AudioClock::Timecode);
2364 nudge_clock->set (_session->frame_rate() * 5, true);
2369 * Not all properties may have been in XML, but
2370 * those that are linked to a private variable may need changing
2375 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2377 yn = _show_measures;
2378 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2379 /* do it twice to force the change */
2380 tact->set_active (!yn);
2381 tact->set_active (yn);
2384 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2385 yn = _follow_playhead;
2387 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2388 if (tact->get_active() != yn) {
2389 tact->set_active (yn);
2393 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2394 yn = _stationary_playhead;
2396 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2397 if (tact->get_active() != yn) {
2398 tact->set_active (yn);
2407 Editor::get_state ()
2409 XMLNode* node = new XMLNode (X_("Editor"));
2412 id().print (buf, sizeof (buf));
2413 node->add_property ("id", buf);
2415 node->add_child_nocopy (Tabbable::get_state());
2417 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2418 node->add_property("edit-horizontal-pane-pos", string(buf));
2419 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2420 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2421 node->add_property("edit-vertical-pane-pos", string(buf));
2423 maybe_add_mixer_strip_width (*node);
2425 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2427 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2428 node->add_property ("zoom", buf);
2429 node->add_property ("snap-to", enum_2_string (_snap_type));
2430 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2431 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2432 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2433 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2434 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2435 node->add_property ("edit-point", enum_2_string (_edit_point));
2436 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2437 node->add_property ("visible-track-count", buf);
2439 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2440 node->add_property ("playhead", buf);
2441 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2442 node->add_property ("left-frame", buf);
2443 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2444 node->add_property ("y-origin", buf);
2446 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2447 node->add_property ("maximised", _maximised ? "yes" : "no");
2448 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2449 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2450 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2451 node->add_property ("mouse-mode", enum2str(mouse_mode));
2452 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2454 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2456 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2457 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2460 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2462 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2463 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2466 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2467 node->add_property (X_("editor-list-page"), buf);
2469 if (button_bindings) {
2470 XMLNode* bb = new XMLNode (X_("Buttons"));
2471 button_bindings->save (*bb);
2472 node->add_child_nocopy (*bb);
2475 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2477 node->add_child_nocopy (selection->get_state ());
2478 node->add_child_nocopy (_regions->get_state ());
2480 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2481 node->add_property ("nudge-clock-value", buf);
2486 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2487 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2489 * @return pair: TimeAxisView that y is over, layer index.
2491 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2492 * in stacked or expanded region display mode, otherwise 0.
2494 std::pair<TimeAxisView *, double>
2495 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2497 if (!trackview_relative_offset) {
2498 y -= _trackview_group->canvas_origin().y;
2502 return std::make_pair ( (TimeAxisView *) 0, 0);
2505 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2507 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2514 return std::make_pair ( (TimeAxisView *) 0, 0);
2517 /** Snap a position to the grid, if appropriate, taking into account current
2518 * grid settings and also the state of any snap modifier keys that may be pressed.
2519 * @param start Position to snap.
2520 * @param event Event to get current key modifier information from, or 0.
2523 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2525 if (!_session || !event) {
2529 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2530 if (_snap_mode == SnapOff) {
2531 snap_to_internal (start, direction, for_mark);
2534 if (_snap_mode != SnapOff) {
2535 snap_to_internal (start, direction, for_mark);
2536 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2537 /* SnapOff, but we pressed the snap_delta modifier */
2538 snap_to_internal (start, direction, for_mark);
2544 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2546 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2550 snap_to_internal (start, direction, for_mark, ensure_snap);
2554 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2556 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2557 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2559 switch (_snap_type) {
2560 case SnapToTimecodeFrame:
2561 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2562 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2563 /* start is already on a whole timecode frame, do nothing */
2564 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2565 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2567 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2571 case SnapToTimecodeSeconds:
2572 if (_session->config.get_timecode_offset_negative()) {
2573 start += _session->config.get_timecode_offset ();
2575 start -= _session->config.get_timecode_offset ();
2577 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2578 (start % one_timecode_second == 0)) {
2579 /* start is already on a whole second, do nothing */
2580 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2581 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2583 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2586 if (_session->config.get_timecode_offset_negative()) {
2587 start -= _session->config.get_timecode_offset ();
2589 start += _session->config.get_timecode_offset ();
2593 case SnapToTimecodeMinutes:
2594 if (_session->config.get_timecode_offset_negative()) {
2595 start += _session->config.get_timecode_offset ();
2597 start -= _session->config.get_timecode_offset ();
2599 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2600 (start % one_timecode_minute == 0)) {
2601 /* start is already on a whole minute, do nothing */
2602 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2603 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2605 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2607 if (_session->config.get_timecode_offset_negative()) {
2608 start -= _session->config.get_timecode_offset ();
2610 start += _session->config.get_timecode_offset ();
2614 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2615 abort(); /*NOTREACHED*/
2620 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2622 const framepos_t one_second = _session->frame_rate();
2623 const framepos_t one_minute = _session->frame_rate() * 60;
2624 framepos_t presnap = start;
2628 switch (_snap_type) {
2629 case SnapToTimecodeFrame:
2630 case SnapToTimecodeSeconds:
2631 case SnapToTimecodeMinutes:
2632 return timecode_snap_to_internal (start, direction, for_mark);
2635 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2636 start % (one_second/75) == 0) {
2637 /* start is already on a whole CD frame, do nothing */
2638 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2639 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2641 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2646 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2647 start % one_second == 0) {
2648 /* start is already on a whole second, do nothing */
2649 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2650 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2652 start = (framepos_t) floor ((double) start / one_second) * one_second;
2657 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2658 start % one_minute == 0) {
2659 /* start is already on a whole minute, do nothing */
2660 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2661 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2663 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2668 start = _session->tempo_map().round_to_bar (start, direction);
2672 start = _session->tempo_map().round_to_beat (start, direction);
2675 case SnapToBeatDiv128:
2676 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2678 case SnapToBeatDiv64:
2679 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2681 case SnapToBeatDiv32:
2682 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2684 case SnapToBeatDiv28:
2685 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2687 case SnapToBeatDiv24:
2688 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2690 case SnapToBeatDiv20:
2691 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2693 case SnapToBeatDiv16:
2694 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2696 case SnapToBeatDiv14:
2697 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2699 case SnapToBeatDiv12:
2700 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2702 case SnapToBeatDiv10:
2703 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2705 case SnapToBeatDiv8:
2706 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2708 case SnapToBeatDiv7:
2709 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2711 case SnapToBeatDiv6:
2712 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2714 case SnapToBeatDiv5:
2715 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2717 case SnapToBeatDiv4:
2718 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2720 case SnapToBeatDiv3:
2721 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2723 case SnapToBeatDiv2:
2724 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2732 _session->locations()->marks_either_side (start, before, after);
2734 if (before == max_framepos && after == max_framepos) {
2735 /* No marks to snap to, so just don't snap */
2737 } else if (before == max_framepos) {
2739 } else if (after == max_framepos) {
2741 } else if (before != max_framepos && after != max_framepos) {
2742 /* have before and after */
2743 if ((start - before) < (after - start)) {
2752 case SnapToRegionStart:
2753 case SnapToRegionEnd:
2754 case SnapToRegionSync:
2755 case SnapToRegionBoundary:
2756 if (!region_boundary_cache.empty()) {
2758 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2759 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2761 if (direction > 0) {
2762 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2764 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2767 if (next != region_boundary_cache.begin ()) {
2772 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2773 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2775 if (start > (p + n) / 2) {
2784 switch (_snap_mode) {
2794 if (presnap > start) {
2795 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2799 } else if (presnap < start) {
2800 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2806 /* handled at entry */
2814 Editor::setup_toolbar ()
2816 HBox* mode_box = manage(new HBox);
2817 mode_box->set_border_width (2);
2818 mode_box->set_spacing(2);
2820 HBox* mouse_mode_box = manage (new HBox);
2821 HBox* mouse_mode_hbox = manage (new HBox);
2822 VBox* mouse_mode_vbox = manage (new VBox);
2823 Alignment* mouse_mode_align = manage (new Alignment);
2825 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2826 mouse_mode_size_group->add_widget (smart_mode_button);
2827 mouse_mode_size_group->add_widget (mouse_move_button);
2828 mouse_mode_size_group->add_widget (mouse_cut_button);
2829 mouse_mode_size_group->add_widget (mouse_select_button);
2830 mouse_mode_size_group->add_widget (mouse_timefx_button);
2831 mouse_mode_size_group->add_widget (mouse_audition_button);
2832 mouse_mode_size_group->add_widget (mouse_draw_button);
2833 mouse_mode_size_group->add_widget (mouse_content_button);
2835 mouse_mode_size_group->add_widget (zoom_in_button);
2836 mouse_mode_size_group->add_widget (zoom_out_button);
2837 mouse_mode_size_group->add_widget (zoom_preset_selector);
2838 mouse_mode_size_group->add_widget (zoom_out_full_button);
2839 mouse_mode_size_group->add_widget (zoom_focus_selector);
2841 mouse_mode_size_group->add_widget (tav_shrink_button);
2842 mouse_mode_size_group->add_widget (tav_expand_button);
2843 mouse_mode_size_group->add_widget (visible_tracks_selector);
2845 mouse_mode_size_group->add_widget (snap_type_selector);
2846 mouse_mode_size_group->add_widget (snap_mode_selector);
2848 mouse_mode_size_group->add_widget (edit_point_selector);
2849 mouse_mode_size_group->add_widget (edit_mode_selector);
2851 mouse_mode_size_group->add_widget (*nudge_clock);
2852 mouse_mode_size_group->add_widget (nudge_forward_button);
2853 mouse_mode_size_group->add_widget (nudge_backward_button);
2855 mouse_mode_hbox->set_spacing (2);
2857 if (!ARDOUR::Profile->get_trx()) {
2858 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2861 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2862 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2864 if (!ARDOUR::Profile->get_mixbus()) {
2865 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2868 if (!ARDOUR::Profile->get_trx()) {
2869 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2870 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2871 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2872 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2875 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2877 mouse_mode_align->add (*mouse_mode_vbox);
2878 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2880 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2882 edit_mode_selector.set_name ("mouse mode button");
2884 if (!ARDOUR::Profile->get_trx()) {
2885 mode_box->pack_start (edit_mode_selector, false, false);
2888 mode_box->pack_start (*mouse_mode_box, false, false);
2892 _zoom_box.set_spacing (2);
2893 _zoom_box.set_border_width (2);
2897 zoom_preset_selector.set_name ("zoom button");
2898 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2899 zoom_preset_selector.set_size_request (42, -1);
2901 zoom_in_button.set_name ("zoom button");
2902 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
2903 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2904 zoom_in_button.set_related_action (act);
2906 zoom_out_button.set_name ("zoom button");
2907 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
2908 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2909 zoom_out_button.set_related_action (act);
2911 zoom_out_full_button.set_name ("zoom button");
2912 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
2913 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2914 zoom_out_full_button.set_related_action (act);
2916 zoom_focus_selector.set_name ("zoom button");
2918 if (ARDOUR::Profile->get_mixbus()) {
2919 _zoom_box.pack_start (zoom_preset_selector, false, false);
2920 } else if (ARDOUR::Profile->get_trx()) {
2921 mode_box->pack_start (zoom_out_button, false, false);
2922 mode_box->pack_start (zoom_in_button, false, false);
2924 _zoom_box.pack_start (zoom_out_button, false, false);
2925 _zoom_box.pack_start (zoom_in_button, false, false);
2926 _zoom_box.pack_start (zoom_out_full_button, false, false);
2927 _zoom_box.pack_start (zoom_focus_selector, false, false);
2930 /* Track zoom buttons */
2931 visible_tracks_selector.set_name ("zoom button");
2932 if (Profile->get_mixbus()) {
2933 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2934 visible_tracks_selector.set_size_request (42, -1);
2936 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2939 tav_expand_button.set_name ("zoom button");
2940 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
2941 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2942 tav_expand_button.set_related_action (act);
2944 tav_shrink_button.set_name ("zoom button");
2945 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
2946 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2947 tav_shrink_button.set_related_action (act);
2949 if (ARDOUR::Profile->get_mixbus()) {
2950 _zoom_box.pack_start (visible_tracks_selector);
2951 } else if (ARDOUR::Profile->get_trx()) {
2952 _zoom_box.pack_start (tav_shrink_button);
2953 _zoom_box.pack_start (tav_expand_button);
2955 _zoom_box.pack_start (visible_tracks_selector);
2956 _zoom_box.pack_start (tav_shrink_button);
2957 _zoom_box.pack_start (tav_expand_button);
2960 snap_box.set_spacing (2);
2961 snap_box.set_border_width (2);
2963 snap_type_selector.set_name ("mouse mode button");
2965 snap_mode_selector.set_name ("mouse mode button");
2967 edit_point_selector.set_name ("mouse mode button");
2969 snap_box.pack_start (snap_mode_selector, false, false);
2970 snap_box.pack_start (snap_type_selector, false, false);
2971 snap_box.pack_start (edit_point_selector, false, false);
2975 HBox *nudge_box = manage (new HBox);
2976 nudge_box->set_spacing (2);
2977 nudge_box->set_border_width (2);
2979 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2980 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2982 nudge_box->pack_start (nudge_backward_button, false, false);
2983 nudge_box->pack_start (nudge_forward_button, false, false);
2984 nudge_box->pack_start (*nudge_clock, false, false);
2987 /* Pack everything in... */
2989 HBox* hbox = manage (new HBox);
2990 hbox->set_spacing(2);
2992 toolbar_hbox.set_spacing (2);
2993 toolbar_hbox.set_border_width (1);
2995 toolbar_hbox.pack_start (*mode_box, false, false);
2996 if (!ARDOUR::Profile->get_trx()) {
2997 toolbar_hbox.pack_start (_zoom_box, false, false);
2998 toolbar_hbox.pack_start (*hbox, false, false);
3001 if (!ARDOUR::Profile->get_trx()) {
3002 hbox->pack_start (snap_box, false, false);
3003 hbox->pack_start (*nudge_box, false, false);
3008 toolbar_base.set_name ("ToolBarBase");
3009 toolbar_base.add (toolbar_hbox);
3011 _toolbar_viewport.add (toolbar_base);
3012 /* stick to the required height but allow width to vary if there's not enough room */
3013 _toolbar_viewport.set_size_request (1, -1);
3015 toolbar_frame.set_shadow_type (SHADOW_OUT);
3016 toolbar_frame.set_name ("BaseFrame");
3017 toolbar_frame.add (_toolbar_viewport);
3021 Editor::build_edit_point_menu ()
3023 using namespace Menu_Helpers;
3025 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3026 if(!Profile->get_mixbus())
3027 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3028 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3030 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3034 Editor::build_edit_mode_menu ()
3036 using namespace Menu_Helpers;
3038 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3039 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3040 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3041 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3043 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3047 Editor::build_snap_mode_menu ()
3049 using namespace Menu_Helpers;
3051 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3052 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3053 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3055 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3059 Editor::build_snap_type_menu ()
3061 using namespace Menu_Helpers;
3063 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3064 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3065 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3066 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3067 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3068 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3069 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3070 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3071 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3072 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3073 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3074 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3075 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3076 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3077 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3078 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3079 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3080 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3081 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3082 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3083 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3084 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3085 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3086 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3087 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3088 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3089 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3090 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3091 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3092 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3094 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3099 Editor::setup_tooltips ()
3101 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3102 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3103 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3104 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3105 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3106 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3107 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3108 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3109 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3110 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3111 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3112 set_tooltip (zoom_in_button, _("Zoom In"));
3113 set_tooltip (zoom_out_button, _("Zoom Out"));
3114 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3115 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3116 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3117 set_tooltip (tav_expand_button, _("Expand Tracks"));
3118 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3119 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3120 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3121 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3122 set_tooltip (edit_point_selector, _("Edit Point"));
3123 set_tooltip (edit_mode_selector, _("Edit Mode"));
3124 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3128 Editor::convert_drop_to_paths (
3129 vector<string>& paths,
3130 const RefPtr<Gdk::DragContext>& /*context*/,
3133 const SelectionData& data,
3137 if (_session == 0) {
3141 vector<string> uris = data.get_uris();
3145 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3146 are actually URI lists. So do it by hand.
3149 if (data.get_target() != "text/plain") {
3153 /* Parse the "uri-list" format that Nautilus provides,
3154 where each pathname is delimited by \r\n.
3156 THERE MAY BE NO NULL TERMINATING CHAR!!!
3159 string txt = data.get_text();
3163 p = (char *) malloc (txt.length() + 1);
3164 txt.copy (p, txt.length(), 0);
3165 p[txt.length()] = '\0';
3171 while (g_ascii_isspace (*p))
3175 while (*q && (*q != '\n') && (*q != '\r')) {
3182 while (q > p && g_ascii_isspace (*q))
3187 uris.push_back (string (p, q - p + 1));
3191 p = strchr (p, '\n');
3203 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3204 if ((*i).substr (0,7) == "file://") {
3205 paths.push_back (Glib::filename_from_uri (*i));
3213 Editor::new_tempo_section ()
3218 Editor::map_transport_state ()
3220 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3222 if (_session && _session->transport_stopped()) {
3223 have_pending_keyboard_selection = false;
3226 update_loop_range_view ();
3232 Editor::begin_selection_op_history ()
3234 selection_op_cmd_depth = 0;
3235 selection_op_history_it = 0;
3237 while(!selection_op_history.empty()) {
3238 delete selection_op_history.front();
3239 selection_op_history.pop_front();
3242 selection_undo_action->set_sensitive (false);
3243 selection_redo_action->set_sensitive (false);
3244 selection_op_history.push_front (&_selection_memento->get_state ());
3248 Editor::begin_reversible_selection_op (string name)
3251 //cerr << name << endl;
3252 /* begin/commit pairs can be nested */
3253 selection_op_cmd_depth++;
3258 Editor::commit_reversible_selection_op ()
3261 if (selection_op_cmd_depth == 1) {
3263 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3265 The user has undone some selection ops and then made a new one,
3266 making anything earlier in the list invalid.
3269 list<XMLNode *>::iterator it = selection_op_history.begin();
3270 list<XMLNode *>::iterator e_it = it;
3271 advance (e_it, selection_op_history_it);
3273 for ( ; it != e_it; ++it) {
3276 selection_op_history.erase (selection_op_history.begin(), e_it);
3279 selection_op_history.push_front (&_selection_memento->get_state ());
3280 selection_op_history_it = 0;
3282 selection_undo_action->set_sensitive (true);
3283 selection_redo_action->set_sensitive (false);
3286 if (selection_op_cmd_depth > 0) {
3287 selection_op_cmd_depth--;
3293 Editor::undo_selection_op ()
3296 selection_op_history_it++;
3298 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3299 if (n == selection_op_history_it) {
3300 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3301 selection_redo_action->set_sensitive (true);
3305 /* is there an earlier entry? */
3306 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3307 selection_undo_action->set_sensitive (false);
3313 Editor::redo_selection_op ()
3316 if (selection_op_history_it > 0) {
3317 selection_op_history_it--;
3320 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3321 if (n == selection_op_history_it) {
3322 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3323 selection_undo_action->set_sensitive (true);
3328 if (selection_op_history_it == 0) {
3329 selection_redo_action->set_sensitive (false);
3335 Editor::begin_reversible_command (string name)
3338 before.push_back (&_selection_memento->get_state ());
3339 _session->begin_reversible_command (name);
3344 Editor::begin_reversible_command (GQuark q)
3347 before.push_back (&_selection_memento->get_state ());
3348 _session->begin_reversible_command (q);
3353 Editor::abort_reversible_command ()
3356 while(!before.empty()) {
3357 delete before.front();
3360 _session->abort_reversible_command ();
3365 Editor::commit_reversible_command ()
3368 if (before.size() == 1) {
3369 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3370 redo_action->set_sensitive(false);
3371 undo_action->set_sensitive(true);
3372 begin_selection_op_history ();
3375 if (before.empty()) {
3376 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3381 _session->commit_reversible_command ();
3386 Editor::history_changed ()
3390 if (undo_action && _session) {
3391 if (_session->undo_depth() == 0) {
3392 label = S_("Command|Undo");
3394 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3396 undo_action->property_label() = label;
3399 if (redo_action && _session) {
3400 if (_session->redo_depth() == 0) {
3402 redo_action->set_sensitive (false);
3404 label = string_compose(_("Redo (%1)"), _session->next_redo());
3405 redo_action->set_sensitive (true);
3407 redo_action->property_label() = label;
3412 Editor::duplicate_range (bool with_dialog)
3416 RegionSelection rs = get_regions_from_selection_and_entered ();
3418 if ( selection->time.length() == 0 && rs.empty()) {
3424 ArdourDialog win (_("Duplicate"));
3425 Label label (_("Number of duplications:"));
3426 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3427 SpinButton spinner (adjustment, 0.0, 1);
3430 win.get_vbox()->set_spacing (12);
3431 win.get_vbox()->pack_start (hbox);
3432 hbox.set_border_width (6);
3433 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3435 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3436 place, visually. so do this by hand.
3439 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3440 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3441 spinner.grab_focus();
3447 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3448 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3449 win.set_default_response (RESPONSE_ACCEPT);
3451 spinner.grab_focus ();
3453 switch (win.run ()) {
3454 case RESPONSE_ACCEPT:
3460 times = adjustment.get_value();
3463 if ((current_mouse_mode() == Editing::MouseRange)) {
3464 if (selection->time.length()) {
3465 duplicate_selection (times);
3467 } else if (get_smart_mode()) {
3468 if (selection->time.length()) {
3469 duplicate_selection (times);
3471 duplicate_some_regions (rs, times);
3473 duplicate_some_regions (rs, times);
3478 Editor::set_edit_mode (EditMode m)
3480 Config->set_edit_mode (m);
3484 Editor::cycle_edit_mode ()
3486 switch (Config->get_edit_mode()) {
3488 if (Profile->get_sae()) {
3489 Config->set_edit_mode (Lock);
3491 Config->set_edit_mode (Ripple);
3496 Config->set_edit_mode (Lock);
3499 Config->set_edit_mode (Slide);
3505 Editor::edit_mode_selection_done ( EditMode m )
3507 Config->set_edit_mode ( m );
3511 Editor::snap_type_selection_done (SnapType snaptype)
3513 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3515 ract->set_active ();
3520 Editor::snap_mode_selection_done (SnapMode mode)
3522 RefPtr<RadioAction> ract = snap_mode_action (mode);
3525 ract->set_active (true);
3530 Editor::cycle_edit_point (bool with_marker)
3532 if(Profile->get_mixbus())
3533 with_marker = false;
3535 switch (_edit_point) {
3537 set_edit_point_preference (EditAtPlayhead);
3539 case EditAtPlayhead:
3541 set_edit_point_preference (EditAtSelectedMarker);
3543 set_edit_point_preference (EditAtMouse);
3546 case EditAtSelectedMarker:
3547 set_edit_point_preference (EditAtMouse);
3553 Editor::edit_point_selection_done (EditPoint ep)
3555 set_edit_point_preference ( ep );
3559 Editor::build_zoom_focus_menu ()
3561 using namespace Menu_Helpers;
3563 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3564 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3565 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3566 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3567 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3568 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3570 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3574 Editor::zoom_focus_selection_done ( ZoomFocus f )
3576 RefPtr<RadioAction> ract = zoom_focus_action (f);
3578 ract->set_active ();
3583 Editor::build_track_count_menu ()
3585 using namespace Menu_Helpers;
3587 if (!Profile->get_mixbus()) {
3588 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3589 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3590 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3591 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3592 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3593 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3594 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3595 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3596 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3597 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3598 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3599 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3600 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3602 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3603 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3604 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3605 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3606 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3607 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3608 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3609 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3610 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3611 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3613 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3614 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3615 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3616 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3617 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3618 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3619 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3620 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3621 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3622 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3623 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3628 Editor::set_zoom_preset (int64_t ms)
3631 temporal_zoom_session();
3635 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3636 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3640 Editor::set_visible_track_count (int32_t n)
3642 _visible_track_count = n;
3644 /* if the canvas hasn't really been allocated any size yet, just
3645 record the desired number of visible tracks and return. when canvas
3646 allocation happens, we will get called again and then we can do the
3650 if (_visible_canvas_height <= 1) {
3656 DisplaySuspender ds;
3658 if (_visible_track_count > 0) {
3659 h = trackviews_height() / _visible_track_count;
3660 std::ostringstream s;
3661 s << _visible_track_count;
3663 } else if (_visible_track_count == 0) {
3665 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3666 if ((*i)->marked_for_display()) {
3670 h = trackviews_height() / n;
3673 /* negative value means that the visible track count has
3674 been overridden by explicit track height changes.
3676 visible_tracks_selector.set_text (X_("*"));
3680 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3681 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3684 if (str != visible_tracks_selector.get_text()) {
3685 visible_tracks_selector.set_text (str);
3690 Editor::override_visible_track_count ()
3692 _visible_track_count = -1;
3693 visible_tracks_selector.set_text ( _("*") );
3697 Editor::edit_controls_button_release (GdkEventButton* ev)
3699 if (Keyboard::is_context_menu_event (ev)) {
3700 ARDOUR_UI::instance()->add_route (current_toplevel());
3701 } else if (ev->button == 1) {
3702 selection->clear_tracks ();
3709 Editor::mouse_select_button_release (GdkEventButton* ev)
3711 /* this handles just right-clicks */
3713 if (ev->button != 3) {
3721 Editor::set_zoom_focus (ZoomFocus f)
3723 string str = zoom_focus_strings[(int)f];
3725 if (str != zoom_focus_selector.get_text()) {
3726 zoom_focus_selector.set_text (str);
3729 if (zoom_focus != f) {
3736 Editor::cycle_zoom_focus ()
3738 switch (zoom_focus) {
3740 set_zoom_focus (ZoomFocusRight);
3742 case ZoomFocusRight:
3743 set_zoom_focus (ZoomFocusCenter);
3745 case ZoomFocusCenter:
3746 set_zoom_focus (ZoomFocusPlayhead);
3748 case ZoomFocusPlayhead:
3749 set_zoom_focus (ZoomFocusMouse);
3751 case ZoomFocusMouse:
3752 set_zoom_focus (ZoomFocusEdit);
3755 set_zoom_focus (ZoomFocusLeft);
3761 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3763 /* recover or initialize pane positions. do this here rather than earlier because
3764 we don't want the positions to change the child allocations, which they seem to do.
3770 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3779 XMLNode* geometry = find_named_node (*node, "geometry");
3781 if (which == static_cast<Paned*> (&edit_pane)) {
3783 if (done & Horizontal) {
3787 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3788 _notebook_shrunk = string_is_affirmative (prop->value ());
3791 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3792 /* initial allocation is 90% to canvas, 10% to notebook */
3793 pos = (int) floor (alloc.get_width() * 0.90f);
3794 snprintf (buf, sizeof(buf), "%d", pos);
3796 pos = atoi (prop->value());
3799 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3800 edit_pane.set_position (pos);
3803 done = (Pane) (done | Horizontal);
3805 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3807 if (done & Vertical) {
3811 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3812 /* initial allocation is 90% to canvas, 10% to summary */
3813 pos = (int) floor (alloc.get_height() * 0.90f);
3814 snprintf (buf, sizeof(buf), "%d", pos);
3817 pos = atoi (prop->value());
3820 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3821 editor_summary_pane.set_position (pos);
3824 done = (Pane) (done | Vertical);
3829 Editor::set_show_measures (bool yn)
3831 if (_show_measures != yn) {
3834 if ((_show_measures = yn) == true) {
3836 tempo_lines->show();
3839 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3840 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3842 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3843 draw_measures (begin, end);
3851 Editor::toggle_follow_playhead ()
3853 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3855 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3856 set_follow_playhead (tact->get_active());
3860 /** @param yn true to follow playhead, otherwise false.
3861 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3864 Editor::set_follow_playhead (bool yn, bool catch_up)
3866 if (_follow_playhead != yn) {
3867 if ((_follow_playhead = yn) == true && catch_up) {
3869 reset_x_origin_to_follow_playhead ();
3876 Editor::toggle_stationary_playhead ()
3878 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3880 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3881 set_stationary_playhead (tact->get_active());
3886 Editor::set_stationary_playhead (bool yn)
3888 if (_stationary_playhead != yn) {
3889 if ((_stationary_playhead = yn) == true) {
3891 // FIXME need a 3.0 equivalent of this 2.X call
3892 // update_current_screen ();
3899 Editor::playlist_selector () const
3901 return *_playlist_selector;
3905 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
3907 if (paste_count == 0) {
3908 /* don't bother calculating an offset that will be zero anyway */
3912 /* calculate basic unsnapped multi-paste offset */
3913 framecnt_t offset = paste_count * duration;
3915 /* snap offset so pos + offset is aligned to the grid */
3916 framepos_t offset_pos = pos + offset;
3917 snap_to(offset_pos, RoundUpMaybe);
3918 offset = offset_pos - pos;
3924 Editor::get_grid_beat_divisions(framepos_t position)
3926 switch (_snap_type) {
3927 case SnapToBeatDiv128: return 128;
3928 case SnapToBeatDiv64: return 64;
3929 case SnapToBeatDiv32: return 32;
3930 case SnapToBeatDiv28: return 28;
3931 case SnapToBeatDiv24: return 24;
3932 case SnapToBeatDiv20: return 20;
3933 case SnapToBeatDiv16: return 16;
3934 case SnapToBeatDiv14: return 14;
3935 case SnapToBeatDiv12: return 12;
3936 case SnapToBeatDiv10: return 10;
3937 case SnapToBeatDiv8: return 8;
3938 case SnapToBeatDiv7: return 7;
3939 case SnapToBeatDiv6: return 6;
3940 case SnapToBeatDiv5: return 5;
3941 case SnapToBeatDiv4: return 4;
3942 case SnapToBeatDiv3: return 3;
3943 case SnapToBeatDiv2: return 2;
3950 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3954 const unsigned divisions = get_grid_beat_divisions(position);
3956 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
3959 switch (_snap_type) {
3961 return Evoral::Beats(1.0);
3964 return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
3972 return Evoral::Beats();
3976 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3980 ret = nudge_clock->current_duration (pos);
3981 next = ret + 1; /* XXXX fix me */
3987 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3989 ArdourDialog dialog (_("Playlist Deletion"));
3990 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3991 "If it is kept, its audio files will not be cleaned.\n"
3992 "If it is deleted, audio files used by it alone will be cleaned."),
3995 dialog.set_position (WIN_POS_CENTER);
3996 dialog.get_vbox()->pack_start (label);
4000 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4001 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4002 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4003 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4004 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4006 // by default gtk uses the left most button
4007 keep->grab_focus ();
4009 switch (dialog.run ()) {
4011 /* keep this and all remaining ones */
4016 /* delete this and all others */
4020 case RESPONSE_ACCEPT:
4021 /* delete the playlist */
4025 case RESPONSE_REJECT:
4026 /* keep the playlist */
4038 Editor::audio_region_selection_covers (framepos_t where)
4040 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4041 if ((*a)->region()->covers (where)) {
4050 Editor::prepare_for_cleanup ()
4052 cut_buffer->clear_regions ();
4053 cut_buffer->clear_playlists ();
4055 selection->clear_regions ();
4056 selection->clear_playlists ();
4058 _regions->suspend_redisplay ();
4062 Editor::finish_cleanup ()
4064 _regions->resume_redisplay ();
4068 Editor::transport_loop_location()
4071 return _session->locations()->auto_loop_location();
4078 Editor::transport_punch_location()
4081 return _session->locations()->auto_punch_location();
4088 Editor::control_layout_scroll (GdkEventScroll* ev)
4090 /* Just forward to the normal canvas scroll method. The coordinate
4091 systems are different but since the canvas is always larger than the
4092 track headers, and aligned with the trackview area, this will work.
4094 In the not too distant future this layout is going away anyway and
4095 headers will be on the canvas.
4097 return canvas_scroll_event (ev, false);
4101 Editor::session_state_saved (string)
4104 _snapshots->redisplay ();
4108 Editor::maximise_editing_space ()
4114 Gtk::Window* toplevel = current_toplevel();
4117 toplevel->fullscreen ();
4123 Editor::restore_editing_space ()
4129 Gtk::Window* toplevel = current_toplevel();
4132 toplevel->unfullscreen();
4138 * Make new playlists for a given track and also any others that belong
4139 * to the same active route group with the `select' property.
4144 Editor::new_playlists (TimeAxisView* v)
4146 begin_reversible_command (_("new playlists"));
4147 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4148 _session->playlists->get (playlists);
4149 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4150 commit_reversible_command ();
4154 * Use a copy of the current playlist for a given track and also any others that belong
4155 * to the same active route group with the `select' property.
4160 Editor::copy_playlists (TimeAxisView* v)
4162 begin_reversible_command (_("copy playlists"));
4163 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4164 _session->playlists->get (playlists);
4165 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4166 commit_reversible_command ();
4169 /** Clear the current playlist for a given track and also any others that belong
4170 * to the same active route group with the `select' property.
4175 Editor::clear_playlists (TimeAxisView* v)
4177 begin_reversible_command (_("clear playlists"));
4178 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4179 _session->playlists->get (playlists);
4180 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4181 commit_reversible_command ();
4185 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4187 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4191 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4193 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4197 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4199 atv.clear_playlist ();
4203 Editor::get_y_origin () const
4205 return vertical_adjustment.get_value ();
4208 /** Queue up a change to the viewport x origin.
4209 * @param frame New x origin.
4212 Editor::reset_x_origin (framepos_t frame)
4214 pending_visual_change.add (VisualChange::TimeOrigin);
4215 pending_visual_change.time_origin = frame;
4216 ensure_visual_change_idle_handler ();
4220 Editor::reset_y_origin (double y)
4222 pending_visual_change.add (VisualChange::YOrigin);
4223 pending_visual_change.y_origin = y;
4224 ensure_visual_change_idle_handler ();
4228 Editor::reset_zoom (framecnt_t spp)
4230 if (spp == samples_per_pixel) {
4234 pending_visual_change.add (VisualChange::ZoomLevel);
4235 pending_visual_change.samples_per_pixel = spp;
4236 ensure_visual_change_idle_handler ();
4240 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4242 reset_x_origin (frame);
4245 if (!no_save_visual) {
4246 undo_visual_stack.push_back (current_visual_state(false));
4250 Editor::VisualState::VisualState (bool with_tracks)
4251 : gui_state (with_tracks ? new GUIObjectState : 0)
4255 Editor::VisualState::~VisualState ()
4260 Editor::VisualState*
4261 Editor::current_visual_state (bool with_tracks)
4263 VisualState* vs = new VisualState (with_tracks);
4264 vs->y_position = vertical_adjustment.get_value();
4265 vs->samples_per_pixel = samples_per_pixel;
4266 vs->leftmost_frame = leftmost_frame;
4267 vs->zoom_focus = zoom_focus;
4270 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4277 Editor::undo_visual_state ()
4279 if (undo_visual_stack.empty()) {
4283 VisualState* vs = undo_visual_stack.back();
4284 undo_visual_stack.pop_back();
4287 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4290 use_visual_state (*vs);
4295 Editor::redo_visual_state ()
4297 if (redo_visual_stack.empty()) {
4301 VisualState* vs = redo_visual_stack.back();
4302 redo_visual_stack.pop_back();
4304 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4305 // why do we check here?
4306 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4309 use_visual_state (*vs);
4314 Editor::swap_visual_state ()
4316 if (undo_visual_stack.empty()) {
4317 redo_visual_state ();
4319 undo_visual_state ();
4324 Editor::use_visual_state (VisualState& vs)
4326 PBD::Unwinder<bool> nsv (no_save_visual, true);
4327 DisplaySuspender ds;
4329 vertical_adjustment.set_value (vs.y_position);
4331 set_zoom_focus (vs.zoom_focus);
4332 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4335 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4337 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4338 (*i)->clear_property_cache();
4339 (*i)->reset_visual_state ();
4343 _routes->update_visibility ();
4346 /** This is the core function that controls the zoom level of the canvas. It is called
4347 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4348 * @param spp new number of samples per pixel
4351 Editor::set_samples_per_pixel (framecnt_t spp)
4357 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4358 const framecnt_t lots_of_pixels = 4000;
4360 /* if the zoom level is greater than what you'd get trying to display 3
4361 * days of audio on a really big screen, then it's too big.
4364 if (spp * lots_of_pixels > three_days) {
4368 samples_per_pixel = spp;
4371 tempo_lines->tempo_map_changed();
4374 bool const showing_time_selection = selection->time.length() > 0;
4376 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4377 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4378 (*i)->reshow_selection (selection->time);
4382 ZoomChanged (); /* EMIT_SIGNAL */
4384 ArdourCanvas::GtkCanvasViewport* c;
4386 c = get_track_canvas();
4388 c->canvas()->zoomed ();
4391 if (playhead_cursor) {
4392 playhead_cursor->set_position (playhead_cursor->current_frame ());
4395 refresh_location_display();
4396 _summary->set_overlays_dirty ();
4398 update_marker_labels ();
4404 Editor::queue_visual_videotimeline_update ()
4407 * pending_visual_change.add (VisualChange::VideoTimeline);
4408 * or maybe even more specific: which videotimeline-image
4409 * currently it calls update_video_timeline() to update
4410 * _all outdated_ images on the video-timeline.
4411 * see 'exposeimg()' in video_image_frame.cc
4413 ensure_visual_change_idle_handler ();
4417 Editor::ensure_visual_change_idle_handler ()
4419 if (pending_visual_change.idle_handler_id < 0) {
4420 // see comment in add_to_idle_resize above.
4421 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4422 pending_visual_change.being_handled = false;
4427 Editor::_idle_visual_changer (void* arg)
4429 return static_cast<Editor*>(arg)->idle_visual_changer ();
4433 Editor::idle_visual_changer ()
4435 /* set_horizontal_position() below (and maybe other calls) call
4436 gtk_main_iteration(), so it's possible that a signal will be handled
4437 half-way through this method. If this signal wants an
4438 idle_visual_changer we must schedule another one after this one, so
4439 mark the idle_handler_id as -1 here to allow that. Also make a note
4440 that we are doing the visual change, so that changes in response to
4441 super-rapid-screen-update can be dropped if we are still processing
4445 pending_visual_change.idle_handler_id = -1;
4446 pending_visual_change.being_handled = true;
4448 VisualChange vc = pending_visual_change;
4450 pending_visual_change.pending = (VisualChange::Type) 0;
4452 visual_changer (vc);
4454 pending_visual_change.being_handled = false;
4456 return 0; /* this is always a one-shot call */
4460 Editor::visual_changer (const VisualChange& vc)
4462 double const last_time_origin = horizontal_position ();
4464 if (vc.pending & VisualChange::ZoomLevel) {
4465 set_samples_per_pixel (vc.samples_per_pixel);
4467 compute_fixed_ruler_scale ();
4469 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4470 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4472 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4473 current_bbt_points_begin, current_bbt_points_end);
4474 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4475 current_bbt_points_begin, current_bbt_points_end);
4476 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4478 update_video_timeline();
4481 if (vc.pending & VisualChange::TimeOrigin) {
4482 set_horizontal_position (vc.time_origin / samples_per_pixel);
4485 if (vc.pending & VisualChange::YOrigin) {
4486 vertical_adjustment.set_value (vc.y_origin);
4489 if (last_time_origin == horizontal_position ()) {
4490 /* changed signal not emitted */
4491 update_fixed_rulers ();
4492 redisplay_tempo (true);
4495 if (!(vc.pending & VisualChange::ZoomLevel)) {
4496 update_video_timeline();
4499 _summary->set_overlays_dirty ();
4502 struct EditorOrderTimeAxisSorter {
4503 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4504 return a->order () < b->order ();
4509 Editor::sort_track_selection (TrackViewList& sel)
4511 EditorOrderTimeAxisSorter cmp;
4516 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4519 framepos_t where = 0;
4520 EditPoint ep = _edit_point;
4522 if (Profile->get_mixbus())
4523 if (ep == EditAtSelectedMarker)
4524 ep = EditAtPlayhead;
4526 if (from_outside_canvas && (ep == EditAtMouse)) {
4527 ep = EditAtPlayhead;
4528 } else if (from_context_menu && (ep == EditAtMouse)) {
4529 return canvas_event_sample (&context_click_event, 0, 0);
4532 if (entered_marker) {
4533 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4534 return entered_marker->position();
4537 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4538 ep = EditAtSelectedMarker;
4541 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4542 ep = EditAtPlayhead;
4546 case EditAtPlayhead:
4547 if (_dragging_playhead) {
4548 where = *_control_scroll_target;
4550 where = _session->audible_frame();
4552 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4555 case EditAtSelectedMarker:
4556 if (!selection->markers.empty()) {
4558 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4561 where = loc->start();
4565 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4573 if (!mouse_frame (where, ignored)) {
4574 /* XXX not right but what can we do ? */
4578 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4586 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4588 if (!_session) return;
4590 begin_reversible_command (cmd);
4594 if ((tll = transport_loop_location()) == 0) {
4595 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4596 XMLNode &before = _session->locations()->get_state();
4597 _session->locations()->add (loc, true);
4598 _session->set_auto_loop_location (loc);
4599 XMLNode &after = _session->locations()->get_state();
4600 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4602 XMLNode &before = tll->get_state();
4603 tll->set_hidden (false, this);
4604 tll->set (start, end);
4605 XMLNode &after = tll->get_state();
4606 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4609 commit_reversible_command ();
4613 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4615 if (!_session) return;
4617 begin_reversible_command (cmd);
4621 if ((tpl = transport_punch_location()) == 0) {
4622 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4623 XMLNode &before = _session->locations()->get_state();
4624 _session->locations()->add (loc, true);
4625 _session->set_auto_punch_location (loc);
4626 XMLNode &after = _session->locations()->get_state();
4627 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4629 XMLNode &before = tpl->get_state();
4630 tpl->set_hidden (false, this);
4631 tpl->set (start, end);
4632 XMLNode &after = tpl->get_state();
4633 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4636 commit_reversible_command ();
4639 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4640 * @param rs List to which found regions are added.
4641 * @param where Time to look at.
4642 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4645 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4647 const TrackViewList* tracks;
4650 tracks = &track_views;
4655 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4657 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4660 boost::shared_ptr<Track> tr;
4661 boost::shared_ptr<Playlist> pl;
4663 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4665 boost::shared_ptr<RegionList> regions = pl->regions_at (
4666 (framepos_t) floor ( (double) where * tr->speed()));
4668 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4669 RegionView* rv = rtv->view()->find_view (*i);
4680 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4682 const TrackViewList* tracks;
4685 tracks = &track_views;
4690 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4691 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4693 boost::shared_ptr<Track> tr;
4694 boost::shared_ptr<Playlist> pl;
4696 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4698 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4699 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4701 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4703 RegionView* rv = rtv->view()->find_view (*i);
4714 /** Get regions using the following method:
4716 * Make a region list using:
4717 * (a) any selected regions
4718 * (b) the intersection of any selected tracks and the edit point(*)
4719 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4721 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4723 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4727 Editor::get_regions_from_selection_and_edit_point ()
4729 RegionSelection regions;
4731 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4732 regions.add (entered_regionview);
4734 regions = selection->regions;
4737 if ( regions.empty() ) {
4738 TrackViewList tracks = selection->tracks;
4740 if (!tracks.empty()) {
4741 /* no region selected or entered, but some selected tracks:
4742 * act on all regions on the selected tracks at the edit point
4744 framepos_t const where = get_preferred_edit_position ();
4745 get_regions_at(regions, where, tracks);
4752 /** Get regions using the following method:
4754 * Make a region list using:
4755 * (a) any selected regions
4756 * (b) the intersection of any selected tracks and the edit point(*)
4757 * (c) if neither exists, then whatever region is under the mouse
4759 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4761 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4764 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4766 RegionSelection regions;
4768 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4769 regions.add (entered_regionview);
4771 regions = selection->regions;
4774 if ( regions.empty() ) {
4775 TrackViewList tracks = selection->tracks;
4777 if (!tracks.empty()) {
4778 /* no region selected or entered, but some selected tracks:
4779 * act on all regions on the selected tracks at the edit point
4781 get_regions_at(regions, pos, tracks);
4788 /** Start with regions that are selected, or the entered regionview if none are selected.
4789 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4790 * of the regions that we started with.
4794 Editor::get_regions_from_selection_and_entered ()
4796 RegionSelection regions = selection->regions;
4798 if (regions.empty() && entered_regionview) {
4799 regions.add (entered_regionview);
4806 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4808 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4809 RouteTimeAxisView* rtav;
4811 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4812 boost::shared_ptr<Playlist> pl;
4813 std::vector<boost::shared_ptr<Region> > results;
4814 boost::shared_ptr<Track> tr;
4816 if ((tr = rtav->track()) == 0) {
4821 if ((pl = (tr->playlist())) != 0) {
4822 boost::shared_ptr<Region> r = pl->region_by_id (id);
4824 RegionView* rv = rtav->view()->find_view (r);
4826 regions.push_back (rv);
4835 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4838 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4839 MidiTimeAxisView* mtav;
4841 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4843 mtav->get_per_region_note_selection (selection);
4850 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4852 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4854 RouteTimeAxisView* tatv;
4856 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4858 boost::shared_ptr<Playlist> pl;
4859 vector<boost::shared_ptr<Region> > results;
4861 boost::shared_ptr<Track> tr;
4863 if ((tr = tatv->track()) == 0) {
4868 if ((pl = (tr->playlist())) != 0) {
4869 if (src_comparison) {
4870 pl->get_source_equivalent_regions (region, results);
4872 pl->get_region_list_equivalent_regions (region, results);
4876 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4877 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4878 regions.push_back (marv);
4887 Editor::show_rhythm_ferret ()
4889 if (rhythm_ferret == 0) {
4890 rhythm_ferret = new RhythmFerret(*this);
4893 rhythm_ferret->set_session (_session);
4894 rhythm_ferret->show ();
4895 rhythm_ferret->present ();
4899 Editor::first_idle ()
4901 MessageDialog* dialog = 0;
4903 if (track_views.size() > 1) {
4904 Timers::TimerSuspender t;
4905 dialog = new MessageDialog (
4906 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4910 ARDOUR_UI::instance()->flush_pending ();
4913 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4917 // first idle adds route children (automation tracks), so we need to redisplay here
4918 _routes->redisplay ();
4922 if (_session->undo_depth() == 0) {
4923 undo_action->set_sensitive(false);
4925 redo_action->set_sensitive(false);
4926 begin_selection_op_history ();
4932 Editor::_idle_resize (gpointer arg)
4934 return ((Editor*)arg)->idle_resize ();
4938 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4940 if (resize_idle_id < 0) {
4941 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
4942 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
4943 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
4945 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
4946 _pending_resize_amount = 0;
4949 /* make a note of the smallest resulting height, so that we can clamp the
4950 lower limit at TimeAxisView::hSmall */
4952 int32_t min_resulting = INT32_MAX;
4954 _pending_resize_amount += h;
4955 _pending_resize_view = view;
4957 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4959 if (selection->tracks.contains (_pending_resize_view)) {
4960 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4961 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4965 if (min_resulting < 0) {
4970 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4971 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4975 /** Handle pending resizing of tracks */
4977 Editor::idle_resize ()
4979 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4981 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4982 selection->tracks.contains (_pending_resize_view)) {
4984 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4985 if (*i != _pending_resize_view) {
4986 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4991 _pending_resize_amount = 0;
4992 _group_tabs->set_dirty ();
4993 resize_idle_id = -1;
5001 ENSURE_GUI_THREAD (*this, &Editor::located);
5004 playhead_cursor->set_position (_session->audible_frame ());
5005 if (_follow_playhead && !_pending_initial_locate) {
5006 reset_x_origin_to_follow_playhead ();
5010 _pending_locate_request = false;
5011 _pending_initial_locate = false;
5015 Editor::region_view_added (RegionView * rv)
5017 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5018 if (rv->region ()->id () == (*pr)) {
5019 selection->add (rv);
5020 selection->regions.pending.erase (pr);
5025 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5027 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5028 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5029 if (rv->region()->id () == (*rnote).first) {
5030 mrv->select_notes ((*rnote).second);
5031 selection->pending_midi_note_selection.erase(rnote);
5037 _summary->set_background_dirty ();
5041 Editor::region_view_removed ()
5043 _summary->set_background_dirty ();
5047 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5049 TrackViewList::const_iterator j = track_views.begin ();
5050 while (j != track_views.end()) {
5051 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5052 if (rtv && rtv->route() == r) {
5063 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5067 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5068 TimeAxisView* tv = axis_view_from_route (*i);
5078 Editor::suspend_route_redisplay ()
5081 _routes->suspend_redisplay();
5086 Editor::resume_route_redisplay ()
5089 _routes->redisplay(); // queue redisplay
5090 _routes->resume_redisplay();
5095 Editor::add_routes (RouteList& routes)
5097 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5099 RouteTimeAxisView *rtv;
5100 list<RouteTimeAxisView*> new_views;
5101 TrackViewList new_selection;
5102 bool from_scratch = (track_views.size() == 0);
5104 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5105 boost::shared_ptr<Route> route = (*x);
5107 if (route->is_auditioner() || route->is_monitor()) {
5111 DataType dt = route->input()->default_type();
5113 if (dt == ARDOUR::DataType::AUDIO) {
5114 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5115 rtv->set_route (route);
5116 } else if (dt == ARDOUR::DataType::MIDI) {
5117 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5118 rtv->set_route (route);
5120 throw unknown_type();
5123 new_views.push_back (rtv);
5124 track_views.push_back (rtv);
5125 new_selection.push_back (rtv);
5127 rtv->effective_gain_display ();
5129 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5130 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5133 if (new_views.size() > 0) {
5134 _routes->routes_added (new_views);
5135 _summary->routes_added (new_views);
5138 if (!from_scratch) {
5139 selection->tracks.clear();
5140 selection->add (new_selection);
5141 begin_selection_op_history();
5144 if (show_editor_mixer_when_tracks_arrive) {
5145 show_editor_mixer (true);
5148 editor_list_button.set_sensitive (true);
5152 Editor::timeaxisview_deleted (TimeAxisView *tv)
5154 if (tv == entered_track) {
5158 if (_session && _session->deletion_in_progress()) {
5159 /* the situation is under control */
5163 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5165 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5167 _routes->route_removed (tv);
5169 TimeAxisView::Children c = tv->get_child_list ();
5170 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5171 if (entered_track == i->get()) {
5176 /* remove it from the list of track views */
5178 TrackViewList::iterator i;
5180 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5181 i = track_views.erase (i);
5184 /* update whatever the current mixer strip is displaying, if revelant */
5186 boost::shared_ptr<Route> route;
5189 route = rtav->route ();
5192 if (current_mixer_strip && current_mixer_strip->route() == route) {
5194 TimeAxisView* next_tv;
5196 if (track_views.empty()) {
5198 } else if (i == track_views.end()) {
5199 next_tv = track_views.front();
5206 set_selected_mixer_strip (*next_tv);
5208 /* make the editor mixer strip go away setting the
5209 * button to inactive (which also unticks the menu option)
5212 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5218 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5220 if (apply_to_selection) {
5221 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5223 TrackSelection::iterator j = i;
5226 hide_track_in_display (*i, false);
5231 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5233 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5234 // this will hide the mixer strip
5235 set_selected_mixer_strip (*tv);
5238 _routes->hide_track_in_display (*tv);
5243 Editor::sync_track_view_list_and_routes ()
5245 track_views = TrackViewList (_routes->views ());
5247 _summary->set_background_dirty();
5248 _group_tabs->set_dirty ();
5250 return false; // do not call again (until needed)
5254 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5256 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5261 /** Find a RouteTimeAxisView by the ID of its route */
5263 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5265 RouteTimeAxisView* v;
5267 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5268 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5269 if(v->route()->id() == id) {
5279 Editor::fit_route_group (RouteGroup *g)
5281 TrackViewList ts = axis_views_from_routes (g->route_list ());
5286 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5288 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5291 _session->cancel_audition ();
5295 if (_session->is_auditioning()) {
5296 _session->cancel_audition ();
5297 if (r == last_audition_region) {
5302 _session->audition_region (r);
5303 last_audition_region = r;
5308 Editor::hide_a_region (boost::shared_ptr<Region> r)
5310 r->set_hidden (true);
5314 Editor::show_a_region (boost::shared_ptr<Region> r)
5316 r->set_hidden (false);
5320 Editor::audition_region_from_region_list ()
5322 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5326 Editor::hide_region_from_region_list ()
5328 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5332 Editor::show_region_in_region_list ()
5334 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5338 Editor::step_edit_status_change (bool yn)
5341 start_step_editing ();
5343 stop_step_editing ();
5348 Editor::start_step_editing ()
5350 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5354 Editor::stop_step_editing ()
5356 step_edit_connection.disconnect ();
5360 Editor::check_step_edit ()
5362 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5363 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5365 mtv->check_step_edit ();
5369 return true; // do it again, till we stop
5373 Editor::scroll_press (Direction dir)
5375 ++_scroll_callbacks;
5377 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5378 /* delay the first auto-repeat */
5384 scroll_backward (1);
5392 scroll_up_one_track ();
5396 scroll_down_one_track ();
5400 /* do hacky auto-repeat */
5401 if (!_scroll_connection.connected ()) {
5403 _scroll_connection = Glib::signal_timeout().connect (
5404 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5407 _scroll_callbacks = 0;
5414 Editor::scroll_release ()
5416 _scroll_connection.disconnect ();
5419 /** Queue a change for the Editor viewport x origin to follow the playhead */
5421 Editor::reset_x_origin_to_follow_playhead ()
5423 framepos_t const frame = playhead_cursor->current_frame ();
5425 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5427 if (_session->transport_speed() < 0) {
5429 if (frame > (current_page_samples() / 2)) {
5430 center_screen (frame-(current_page_samples()/2));
5432 center_screen (current_page_samples()/2);
5439 if (frame < leftmost_frame) {
5441 if (_session->transport_rolling()) {
5442 /* rolling; end up with the playhead at the right of the page */
5443 l = frame - current_page_samples ();
5445 /* not rolling: end up with the playhead 1/4 of the way along the page */
5446 l = frame - current_page_samples() / 4;
5450 if (_session->transport_rolling()) {
5451 /* rolling: end up with the playhead on the left of the page */
5454 /* not rolling: end up with the playhead 3/4 of the way along the page */
5455 l = frame - 3 * current_page_samples() / 4;
5463 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5469 Editor::super_rapid_screen_update ()
5471 if (!_session || !_session->engine().running()) {
5475 /* METERING / MIXER STRIPS */
5477 /* update track meters, if required */
5478 if (contents().is_mapped() && meters_running) {
5479 RouteTimeAxisView* rtv;
5480 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5481 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5482 rtv->fast_update ();
5487 /* and any current mixer strip */
5488 if (current_mixer_strip) {
5489 current_mixer_strip->fast_update ();
5492 /* PLAYHEAD AND VIEWPORT */
5494 framepos_t const frame = _session->audible_frame();
5496 /* There are a few reasons why we might not update the playhead / viewport stuff:
5498 * 1. we don't update things when there's a pending locate request, otherwise
5499 * when the editor requests a locate there is a chance that this method
5500 * will move the playhead before the locate request is processed, causing
5502 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5503 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5506 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5508 last_update_frame = frame;
5510 if (!_dragging_playhead) {
5511 playhead_cursor->set_position (frame);
5514 if (!_stationary_playhead) {
5516 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5517 /* We only do this if we aren't already
5518 handling a visual change (ie if
5519 pending_visual_change.being_handled is
5520 false) so that these requests don't stack
5521 up there are too many of them to handle in
5524 reset_x_origin_to_follow_playhead ();
5529 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5530 framepos_t const frame = playhead_cursor->current_frame ();
5531 double target = ((double)frame - (double)current_page_samples()/2.0);
5532 if (target <= 0.0) {
5535 // compare to EditorCursor::set_position()
5536 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5537 double const new_pos = sample_to_pixel_unrounded (target);
5538 if (rint (new_pos) != rint (old_pos)) {
5539 reset_x_origin (pixel_to_sample (floor (new_pos)));
5550 Editor::session_going_away ()
5552 _have_idled = false;
5554 _session_connections.drop_connections ();
5556 super_rapid_screen_update_connection.disconnect ();
5558 selection->clear ();
5559 cut_buffer->clear ();
5561 clicked_regionview = 0;
5562 clicked_axisview = 0;
5563 clicked_routeview = 0;
5564 entered_regionview = 0;
5566 last_update_frame = 0;
5569 playhead_cursor->hide ();
5571 /* rip everything out of the list displays */
5575 _route_groups->clear ();
5577 /* do this first so that deleting a track doesn't reset cms to null
5578 and thus cause a leak.
5581 if (current_mixer_strip) {
5582 if (current_mixer_strip->get_parent() != 0) {
5583 global_hpacker.remove (*current_mixer_strip);
5585 delete current_mixer_strip;
5586 current_mixer_strip = 0;
5589 /* delete all trackviews */
5591 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5594 track_views.clear ();
5596 nudge_clock->set_session (0);
5598 editor_list_button.set_active(false);
5599 editor_list_button.set_sensitive(false);
5601 /* clear tempo/meter rulers */
5602 remove_metric_marks ();
5604 clear_marker_display ();
5606 stop_step_editing ();
5610 /* get rid of any existing editor mixer strip */
5612 WindowTitle title(Glib::get_application_name());
5613 title += _("Editor");
5615 own_window()->set_title (title.get_string());
5618 SessionHandlePtr::session_going_away ();
5623 Editor::show_editor_list (bool yn)
5626 _the_notebook.show ();
5628 _the_notebook.hide ();
5633 Editor::change_region_layering_order (bool from_context_menu)
5635 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5637 if (!clicked_routeview) {
5638 if (layering_order_editor) {
5639 layering_order_editor->hide ();
5644 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5650 boost::shared_ptr<Playlist> pl = track->playlist();
5656 if (layering_order_editor == 0) {
5657 layering_order_editor = new RegionLayeringOrderEditor (*this);
5660 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5661 layering_order_editor->maybe_present ();
5665 Editor::update_region_layering_order_editor ()
5667 if (layering_order_editor && layering_order_editor->is_visible ()) {
5668 change_region_layering_order (true);
5673 Editor::setup_fade_images ()
5675 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5676 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5677 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5678 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5679 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5681 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5682 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5683 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5684 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5685 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5687 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5688 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5689 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5690 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5691 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5693 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5694 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5695 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5696 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5697 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5701 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5703 Editor::action_menu_item (std::string const & name)
5705 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5708 return *manage (a->create_menu_item ());
5712 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5714 EventBox* b = manage (new EventBox);
5715 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5716 Label* l = manage (new Label (name));
5720 _the_notebook.append_page (widget, *b);
5724 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5726 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5727 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5730 if (ev->type == GDK_2BUTTON_PRESS) {
5732 /* double-click on a notebook tab shrinks or expands the notebook */
5734 if (_notebook_shrunk) {
5735 if (pre_notebook_shrink_pane_width) {
5736 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5738 _notebook_shrunk = false;
5740 pre_notebook_shrink_pane_width = edit_pane.get_position();
5742 /* this expands the LHS of the edit pane to cover the notebook
5743 PAGE but leaves the tabs visible.
5745 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5746 _notebook_shrunk = true;
5754 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5756 using namespace Menu_Helpers;
5758 MenuList& items = _control_point_context_menu.items ();
5761 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5762 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5763 if (!can_remove_control_point (item)) {
5764 items.back().set_sensitive (false);
5767 _control_point_context_menu.popup (event->button.button, event->button.time);
5771 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5773 using namespace Menu_Helpers;
5775 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5780 /* We need to get the selection here and pass it to the operations, since
5781 popping up the menu will cause a region leave event which clears
5782 entered_regionview. */
5784 MidiRegionView& mrv = note->region_view();
5785 const RegionSelection rs = get_regions_from_selection_and_entered ();
5786 const uint32_t sel_size = mrv.selection_size ();
5788 MenuList& items = _note_context_menu.items();
5792 items.push_back(MenuElem(_("Delete"),
5793 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5796 items.push_back(MenuElem(_("Edit..."),
5797 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5798 if (sel_size != 1) {
5799 items.back().set_sensitive (false);
5802 items.push_back(MenuElem(_("Transpose..."),
5803 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
5806 items.push_back(MenuElem(_("Legatize"),
5807 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5809 items.back().set_sensitive (false);
5812 items.push_back(MenuElem(_("Quantize..."),
5813 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5815 items.push_back(MenuElem(_("Remove Overlap"),
5816 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5818 items.back().set_sensitive (false);
5821 items.push_back(MenuElem(_("Transform..."),
5822 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5824 _note_context_menu.popup (event->button.button, event->button.time);
5828 Editor::zoom_vertical_modifier_released()
5830 _stepping_axis_view = 0;
5834 Editor::ui_parameter_changed (string parameter)
5836 if (parameter == "icon-set") {
5837 while (!_cursor_stack.empty()) {
5838 _cursor_stack.pop_back();
5840 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
5841 _cursor_stack.push_back(_cursors->grabber);
5842 } else if (parameter == "draggable-playhead") {
5843 if (_verbose_cursor) {
5844 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
5850 Editor::use_own_window (bool and_fill_it)
5852 bool new_window = !own_window();
5854 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
5856 if (win && new_window) {
5857 win->set_name ("EditorWindow");
5859 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
5861 // win->signal_realize().connect (*this, &Editor::on_realize);
5862 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
5863 win->set_data ("ardour-bindings", bindings);
5868 DisplaySuspender ds;
5869 contents().show_all ();
5871 /* XXX: this is a bit unfortunate; it would probably
5872 be nicer if we could just call show () above rather
5873 than needing the show_all ()
5876 /* re-hide stuff if necessary */
5877 editor_list_button_toggled ();
5878 parameter_changed ("show-summary");
5879 parameter_changed ("show-group-tabs");
5880 parameter_changed ("show-zoom-tools");
5882 /* now reset all audio_time_axis heights, because widgets might need
5888 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5889 tv = (static_cast<TimeAxisView*>(*i));
5890 tv->reset_height ();
5893 if (current_mixer_strip) {
5894 current_mixer_strip->hide_things ();
5895 current_mixer_strip->parameter_changed ("mixer-element-visibility");