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)
464 , myactions (X_("editor"))
466 /* we are a singleton */
468 PublicEditor::_instance = this;
472 last_event_time.tv_sec = 0;
473 last_event_time.tv_usec = 0;
475 selection_op_history.clear();
478 snap_type_strings = I18N (_snap_type_strings);
479 snap_mode_strings = I18N (_snap_mode_strings);
480 zoom_focus_strings = I18N (_zoom_focus_strings);
481 edit_mode_strings = I18N (_edit_mode_strings);
482 edit_point_strings = I18N (_edit_point_strings);
483 #ifdef USE_RUBBERBAND
484 rb_opt_strings = I18N (_rb_opt_strings);
488 build_edit_mode_menu();
489 build_zoom_focus_menu();
490 build_track_count_menu();
491 build_snap_mode_menu();
492 build_snap_type_menu();
493 build_edit_point_menu();
495 location_marker_color = UIConfiguration::instance().color ("location marker");
496 location_range_color = UIConfiguration::instance().color ("location range");
497 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
498 location_loop_color = UIConfiguration::instance().color ("location loop");
499 location_punch_color = UIConfiguration::instance().color ("location punch");
501 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
503 TimeAxisView::setup_sizes ();
504 ArdourMarker::setup_sizes (timebar_height);
506 bbt_label.set_name ("EditorRulerLabel");
507 bbt_label.set_size_request (-1, (int)timebar_height);
508 bbt_label.set_alignment (1.0, 0.5);
509 bbt_label.set_padding (5,0);
511 bbt_label.set_no_show_all();
512 minsec_label.set_name ("EditorRulerLabel");
513 minsec_label.set_size_request (-1, (int)timebar_height);
514 minsec_label.set_alignment (1.0, 0.5);
515 minsec_label.set_padding (5,0);
516 minsec_label.hide ();
517 minsec_label.set_no_show_all();
518 timecode_label.set_name ("EditorRulerLabel");
519 timecode_label.set_size_request (-1, (int)timebar_height);
520 timecode_label.set_alignment (1.0, 0.5);
521 timecode_label.set_padding (5,0);
522 timecode_label.hide ();
523 timecode_label.set_no_show_all();
524 samples_label.set_name ("EditorRulerLabel");
525 samples_label.set_size_request (-1, (int)timebar_height);
526 samples_label.set_alignment (1.0, 0.5);
527 samples_label.set_padding (5,0);
528 samples_label.hide ();
529 samples_label.set_no_show_all();
531 tempo_label.set_name ("EditorRulerLabel");
532 tempo_label.set_size_request (-1, (int)timebar_height);
533 tempo_label.set_alignment (1.0, 0.5);
534 tempo_label.set_padding (5,0);
536 tempo_label.set_no_show_all();
538 meter_label.set_name ("EditorRulerLabel");
539 meter_label.set_size_request (-1, (int)timebar_height);
540 meter_label.set_alignment (1.0, 0.5);
541 meter_label.set_padding (5,0);
543 meter_label.set_no_show_all();
545 if (Profile->get_trx()) {
546 mark_label.set_text (_("Markers"));
548 mark_label.set_name ("EditorRulerLabel");
549 mark_label.set_size_request (-1, (int)timebar_height);
550 mark_label.set_alignment (1.0, 0.5);
551 mark_label.set_padding (5,0);
553 mark_label.set_no_show_all();
555 cd_mark_label.set_name ("EditorRulerLabel");
556 cd_mark_label.set_size_request (-1, (int)timebar_height);
557 cd_mark_label.set_alignment (1.0, 0.5);
558 cd_mark_label.set_padding (5,0);
559 cd_mark_label.hide();
560 cd_mark_label.set_no_show_all();
562 videotl_bar_height = 4;
563 videotl_label.set_name ("EditorRulerLabel");
564 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
565 videotl_label.set_alignment (1.0, 0.5);
566 videotl_label.set_padding (5,0);
567 videotl_label.hide();
568 videotl_label.set_no_show_all();
570 range_mark_label.set_name ("EditorRulerLabel");
571 range_mark_label.set_size_request (-1, (int)timebar_height);
572 range_mark_label.set_alignment (1.0, 0.5);
573 range_mark_label.set_padding (5,0);
574 range_mark_label.hide();
575 range_mark_label.set_no_show_all();
577 transport_mark_label.set_name ("EditorRulerLabel");
578 transport_mark_label.set_size_request (-1, (int)timebar_height);
579 transport_mark_label.set_alignment (1.0, 0.5);
580 transport_mark_label.set_padding (5,0);
581 transport_mark_label.hide();
582 transport_mark_label.set_no_show_all();
584 initialize_canvas ();
586 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
588 _summary = new EditorSummary (this);
590 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
591 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
593 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
595 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
596 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
598 edit_controls_vbox.set_spacing (0);
599 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
600 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
602 HBox* h = manage (new HBox);
603 _group_tabs = new EditorGroupTabs (this);
604 if (!ARDOUR::Profile->get_trx()) {
605 h->pack_start (*_group_tabs, PACK_SHRINK);
607 h->pack_start (edit_controls_vbox);
608 controls_layout.add (*h);
610 controls_layout.set_name ("EditControlsBase");
611 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
612 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
613 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
615 _cursors = new MouseCursors;
616 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
617 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
619 /* Push default cursor to ever-present bottom of cursor stack. */
620 push_canvas_cursor(_cursors->grabber);
622 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
624 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
625 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
626 pad_line_1->set_outline_color (0xFF0000FF);
632 edit_packer.set_col_spacings (0);
633 edit_packer.set_row_spacings (0);
634 edit_packer.set_homogeneous (false);
635 edit_packer.set_border_width (0);
636 edit_packer.set_name ("EditorWindow");
638 time_bars_event_box.add (time_bars_vbox);
639 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
640 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
642 /* labels for the time bars */
643 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
645 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
647 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
649 bottom_hbox.set_border_width (2);
650 bottom_hbox.set_spacing (3);
652 _route_groups = new EditorRouteGroups (this);
653 _routes = new EditorRoutes (this);
654 _regions = new EditorRegions (this);
655 _snapshots = new EditorSnapshots (this);
656 _locations = new EditorLocations (this);
658 /* these are static location signals */
660 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
661 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
662 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
664 add_notebook_page (_("Regions"), _regions->widget ());
665 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
666 add_notebook_page (_("Snapshots"), _snapshots->widget ());
667 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
668 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
670 _the_notebook.set_show_tabs (true);
671 _the_notebook.set_scrollable (true);
672 _the_notebook.popup_disable ();
673 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
674 _the_notebook.show_all ();
676 _notebook_shrunk = false;
678 editor_summary_pane.pack1(edit_packer);
680 Button* summary_arrows_left_left = manage (new Button);
681 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
682 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
683 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
685 Button* summary_arrows_left_right = manage (new Button);
686 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
687 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
688 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
690 VBox* summary_arrows_left = manage (new VBox);
691 summary_arrows_left->pack_start (*summary_arrows_left_left);
692 summary_arrows_left->pack_start (*summary_arrows_left_right);
694 Button* summary_arrows_right_up = manage (new Button);
695 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
696 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
697 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
699 Button* summary_arrows_right_down = manage (new Button);
700 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
701 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
702 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
704 VBox* summary_arrows_right = manage (new VBox);
705 summary_arrows_right->pack_start (*summary_arrows_right_up);
706 summary_arrows_right->pack_start (*summary_arrows_right_down);
708 Frame* summary_frame = manage (new Frame);
709 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
711 summary_frame->add (*_summary);
712 summary_frame->show ();
714 _summary_hbox.pack_start (*summary_arrows_left, false, false);
715 _summary_hbox.pack_start (*summary_frame, true, true);
716 _summary_hbox.pack_start (*summary_arrows_right, false, false);
718 if (!ARDOUR::Profile->get_trx()) {
719 editor_summary_pane.pack2 (_summary_hbox);
722 edit_pane.pack1 (editor_summary_pane, true, true);
723 if (!ARDOUR::Profile->get_trx()) {
724 edit_pane.pack2 (_the_notebook, false, true);
727 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
729 /* XXX: editor_summary_pane might need similar to the edit_pane */
731 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
733 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
734 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
736 top_hbox.pack_start (toolbar_frame);
738 HBox *hbox = manage (new HBox);
739 hbox->pack_start (edit_pane, true, true);
741 global_vpacker.pack_start (top_hbox, false, false);
742 global_vpacker.pack_start (*hbox, true, true);
743 global_hpacker.pack_start (global_vpacker, true, true);
745 /* need to show the "contents" widget so that notebook will show if tab is switched to
748 global_hpacker.show ();
750 /* register actions now so that set_state() can find them and set toggles/checks etc */
757 _playlist_selector = new PlaylistSelector();
758 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
760 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
764 nudge_forward_button.set_name ("nudge button");
765 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
767 nudge_backward_button.set_name ("nudge button");
768 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
770 fade_context_menu.set_name ("ArdourContextMenu");
772 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
774 /* allow external control surfaces/protocols to do various things */
776 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
777 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
778 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
779 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
780 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
781 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
782 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
783 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
784 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
785 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
786 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
787 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
788 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
789 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
791 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
792 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
793 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
794 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
795 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
797 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
799 /* problematic: has to return a value and thus cannot be x-thread */
801 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
803 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
804 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
806 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
808 _ignore_region_action = false;
809 _last_region_menu_was_main = false;
810 _popup_region_menu_item = 0;
812 _ignore_follow_edits = false;
814 _show_marker_lines = false;
816 /* Button bindings */
818 button_bindings = new Bindings ("editor-mouse");
820 XMLNode* node = button_settings();
822 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
823 button_bindings->load_operation (**i);
829 /* grab current parameter state */
830 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
831 UIConfiguration::instance().map_parameters (pc);
833 setup_fade_images ();
840 delete button_bindings;
842 delete _route_groups;
843 delete _track_canvas_viewport;
846 delete quantize_dialog;
852 delete _playlist_selector;
854 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
860 Editor::button_settings () const
862 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
863 XMLNode* node = find_named_node (*settings, X_("Buttons"));
866 node = new XMLNode (X_("Buttons"));
873 Editor::get_smart_mode () const
875 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
879 Editor::catch_vanishing_regionview (RegionView *rv)
881 /* note: the selection will take care of the vanishing
882 audioregionview by itself.
885 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
889 if (clicked_regionview == rv) {
890 clicked_regionview = 0;
893 if (entered_regionview == rv) {
894 set_entered_regionview (0);
897 if (!_all_region_actions_sensitized) {
898 sensitize_all_region_actions (true);
903 Editor::set_entered_regionview (RegionView* rv)
905 if (rv == entered_regionview) {
909 if (entered_regionview) {
910 entered_regionview->exited ();
913 entered_regionview = rv;
915 if (entered_regionview != 0) {
916 entered_regionview->entered ();
919 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
920 /* This RegionView entry might have changed what region actions
921 are allowed, so sensitize them all in case a key is pressed.
923 sensitize_all_region_actions (true);
928 Editor::set_entered_track (TimeAxisView* tav)
931 entered_track->exited ();
937 entered_track->entered ();
942 Editor::instant_save ()
944 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
949 _session->add_instant_xml(get_state());
951 Config->add_instant_xml(get_state());
956 Editor::control_vertical_zoom_in_all ()
958 tav_zoom_smooth (false, true);
962 Editor::control_vertical_zoom_out_all ()
964 tav_zoom_smooth (true, true);
968 Editor::control_vertical_zoom_in_selected ()
970 tav_zoom_smooth (false, false);
974 Editor::control_vertical_zoom_out_selected ()
976 tav_zoom_smooth (true, false);
980 Editor::control_view (uint32_t view)
982 goto_visual_state (view);
986 Editor::control_unselect ()
988 selection->clear_tracks ();
992 Editor::control_select (uint32_t rid, Selection::Operation op)
994 /* handles the (static) signal from the ControlProtocol class that
995 * requests setting the selected track to a given RID
1002 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1008 TimeAxisView* tav = axis_view_from_route (r);
1012 case Selection::Add:
1013 selection->add (tav);
1015 case Selection::Toggle:
1016 selection->toggle (tav);
1018 case Selection::Extend:
1020 case Selection::Set:
1021 selection->set (tav);
1025 selection->clear_tracks ();
1030 Editor::control_step_tracks_up ()
1032 scroll_tracks_up_line ();
1036 Editor::control_step_tracks_down ()
1038 scroll_tracks_down_line ();
1042 Editor::control_scroll (float fraction)
1044 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1050 double step = fraction * current_page_samples();
1053 _control_scroll_target is an optional<T>
1055 it acts like a pointer to an framepos_t, with
1056 a operator conversion to boolean to check
1057 that it has a value could possibly use
1058 playhead_cursor->current_frame to store the
1059 value and a boolean in the class to know
1060 when it's out of date
1063 if (!_control_scroll_target) {
1064 _control_scroll_target = _session->transport_frame();
1065 _dragging_playhead = true;
1068 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1069 *_control_scroll_target = 0;
1070 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1071 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1073 *_control_scroll_target += (framepos_t) trunc (step);
1076 /* move visuals, we'll catch up with it later */
1078 playhead_cursor->set_position (*_control_scroll_target);
1079 UpdateAllTransportClocks (*_control_scroll_target);
1081 if (*_control_scroll_target > (current_page_samples() / 2)) {
1082 /* try to center PH in window */
1083 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1089 Now we do a timeout to actually bring the session to the right place
1090 according to the playhead. This is to avoid reading disk buffers on every
1091 call to control_scroll, which is driven by ScrollTimeline and therefore
1092 probably by a control surface wheel which can generate lots of events.
1094 /* cancel the existing timeout */
1096 control_scroll_connection.disconnect ();
1098 /* add the next timeout */
1100 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1104 Editor::deferred_control_scroll (framepos_t /*target*/)
1106 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1107 // reset for next stream
1108 _control_scroll_target = boost::none;
1109 _dragging_playhead = false;
1114 Editor::access_action (std::string action_group, std::string action_item)
1120 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1123 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1131 Editor::on_realize ()
1135 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1136 start_lock_event_timing ();
1141 Editor::start_lock_event_timing ()
1143 /* check if we should lock the GUI every 30 seconds */
1145 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1149 Editor::generic_event_handler (GdkEvent* ev)
1152 case GDK_BUTTON_PRESS:
1153 case GDK_BUTTON_RELEASE:
1154 case GDK_MOTION_NOTIFY:
1156 case GDK_KEY_RELEASE:
1157 if (contents().is_mapped()) {
1158 gettimeofday (&last_event_time, 0);
1162 case GDK_LEAVE_NOTIFY:
1163 switch (ev->crossing.detail) {
1164 case GDK_NOTIFY_UNKNOWN:
1165 case GDK_NOTIFY_INFERIOR:
1166 case GDK_NOTIFY_ANCESTOR:
1168 case GDK_NOTIFY_VIRTUAL:
1169 case GDK_NOTIFY_NONLINEAR:
1170 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1171 /* leaving window, so reset focus, thus ending any and
1172 all text entry operations.
1187 Editor::lock_timeout_callback ()
1189 struct timeval now, delta;
1191 gettimeofday (&now, 0);
1193 timersub (&now, &last_event_time, &delta);
1195 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1197 /* don't call again. Returning false will effectively
1198 disconnect us from the timer callback.
1200 unlock() will call start_lock_event_timing() to get things
1210 Editor::map_position_change (framepos_t frame)
1212 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1214 if (_session == 0) {
1218 if (_follow_playhead) {
1219 center_screen (frame);
1222 playhead_cursor->set_position (frame);
1226 Editor::center_screen (framepos_t frame)
1228 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1230 /* if we're off the page, then scroll.
1233 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1234 center_screen_internal (frame, page);
1239 Editor::center_screen_internal (framepos_t frame, float page)
1244 frame -= (framepos_t) page;
1249 reset_x_origin (frame);
1254 Editor::update_title ()
1256 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1258 if (!own_window()) {
1263 bool dirty = _session->dirty();
1265 string session_name;
1267 if (_session->snap_name() != _session->name()) {
1268 session_name = _session->snap_name();
1270 session_name = _session->name();
1274 session_name = "*" + session_name;
1277 WindowTitle title(session_name);
1278 title += Glib::get_application_name();
1279 own_window()->set_title (title.get_string());
1281 /* ::session_going_away() will have taken care of it */
1286 Editor::set_session (Session *t)
1288 SessionHandlePtr::set_session (t);
1294 _playlist_selector->set_session (_session);
1295 nudge_clock->set_session (_session);
1296 _summary->set_session (_session);
1297 _group_tabs->set_session (_session);
1298 _route_groups->set_session (_session);
1299 _regions->set_session (_session);
1300 _snapshots->set_session (_session);
1301 _routes->set_session (_session);
1302 _locations->set_session (_session);
1304 if (rhythm_ferret) {
1305 rhythm_ferret->set_session (_session);
1308 if (analysis_window) {
1309 analysis_window->set_session (_session);
1313 sfbrowser->set_session (_session);
1316 compute_fixed_ruler_scale ();
1318 /* Make sure we have auto loop and auto punch ranges */
1320 Location* loc = _session->locations()->auto_loop_location();
1322 loc->set_name (_("Loop"));
1325 loc = _session->locations()->auto_punch_location();
1328 loc->set_name (_("Punch"));
1331 refresh_location_display ();
1333 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1334 the selected Marker; this needs the LocationMarker list to be available.
1336 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1337 set_state (*node, Stateful::loading_state_version);
1339 /* catch up with the playhead */
1341 _session->request_locate (playhead_cursor->current_frame ());
1342 _pending_initial_locate = true;
1346 /* These signals can all be emitted by a non-GUI thread. Therefore the
1347 handlers for them must not attempt to directly interact with the GUI,
1348 but use PBD::Signal<T>::connect() which accepts an event loop
1349 ("context") where the handler will be asked to run.
1352 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1353 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1354 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1355 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1356 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1357 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1358 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1359 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1360 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1361 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1362 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1363 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1364 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1366 playhead_cursor->show ();
1368 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1369 Config->map_parameters (pc);
1370 _session->config.map_parameters (pc);
1372 restore_ruler_visibility ();
1373 //tempo_map_changed (PropertyChange (0));
1374 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1376 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1377 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1380 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1381 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1384 switch (_snap_type) {
1385 case SnapToRegionStart:
1386 case SnapToRegionEnd:
1387 case SnapToRegionSync:
1388 case SnapToRegionBoundary:
1389 build_region_boundary_cache ();
1396 /* register for undo history */
1397 _session->register_with_memento_command_factory(id(), this);
1398 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1400 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1402 start_updating_meters ();
1406 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1408 if (a->get_name() == "RegionMenu") {
1409 /* When the main menu's region menu is opened, we setup the actions so that they look right
1410 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1411 so we resensitize all region actions when the entered regionview or the region selection
1412 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1413 happens after the region context menu is opened. So we set a flag here, too.
1417 sensitize_the_right_region_actions ();
1418 _last_region_menu_was_main = true;
1423 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1425 using namespace Menu_Helpers;
1427 void (Editor::*emf)(FadeShape);
1428 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1431 images = &_xfade_in_images;
1432 emf = &Editor::set_fade_in_shape;
1434 images = &_xfade_out_images;
1435 emf = &Editor::set_fade_out_shape;
1440 _("Linear (for highly correlated material)"),
1441 *(*images)[FadeLinear],
1442 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1446 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1450 _("Constant power"),
1451 *(*images)[FadeConstantPower],
1452 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1455 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1460 *(*images)[FadeSymmetric],
1461 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1465 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1470 *(*images)[FadeSlow],
1471 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1474 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1479 *(*images)[FadeFast],
1480 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1483 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1486 /** Pop up a context menu for when the user clicks on a start crossfade */
1488 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1490 using namespace Menu_Helpers;
1491 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1496 MenuList& items (xfade_in_context_menu.items());
1499 if (arv->audio_region()->fade_in_active()) {
1500 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1502 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1505 items.push_back (SeparatorElem());
1506 fill_xfade_menu (items, true);
1508 xfade_in_context_menu.popup (button, time);
1511 /** Pop up a context menu for when the user clicks on an end crossfade */
1513 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1515 using namespace Menu_Helpers;
1516 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1521 MenuList& items (xfade_out_context_menu.items());
1524 if (arv->audio_region()->fade_out_active()) {
1525 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1527 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1530 items.push_back (SeparatorElem());
1531 fill_xfade_menu (items, false);
1533 xfade_out_context_menu.popup (button, time);
1537 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1539 using namespace Menu_Helpers;
1540 Menu* (Editor::*build_menu_function)();
1543 switch (item_type) {
1545 case RegionViewName:
1546 case RegionViewNameHighlight:
1547 case LeftFrameHandle:
1548 case RightFrameHandle:
1549 if (with_selection) {
1550 build_menu_function = &Editor::build_track_selection_context_menu;
1552 build_menu_function = &Editor::build_track_region_context_menu;
1557 if (with_selection) {
1558 build_menu_function = &Editor::build_track_selection_context_menu;
1560 build_menu_function = &Editor::build_track_context_menu;
1565 if (clicked_routeview->track()) {
1566 build_menu_function = &Editor::build_track_context_menu;
1568 build_menu_function = &Editor::build_track_bus_context_menu;
1573 /* probably shouldn't happen but if it does, we don't care */
1577 menu = (this->*build_menu_function)();
1578 menu->set_name ("ArdourContextMenu");
1580 /* now handle specific situations */
1582 switch (item_type) {
1584 case RegionViewName:
1585 case RegionViewNameHighlight:
1586 case LeftFrameHandle:
1587 case RightFrameHandle:
1588 if (!with_selection) {
1589 if (region_edit_menu_split_item) {
1590 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1591 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1593 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1596 if (region_edit_menu_split_multichannel_item) {
1597 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1598 region_edit_menu_split_multichannel_item->set_sensitive (true);
1600 region_edit_menu_split_multichannel_item->set_sensitive (false);
1613 /* probably shouldn't happen but if it does, we don't care */
1617 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1619 /* Bounce to disk */
1621 using namespace Menu_Helpers;
1622 MenuList& edit_items = menu->items();
1624 edit_items.push_back (SeparatorElem());
1626 switch (clicked_routeview->audio_track()->freeze_state()) {
1627 case AudioTrack::NoFreeze:
1628 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1631 case AudioTrack::Frozen:
1632 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1635 case AudioTrack::UnFrozen:
1636 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1642 if (item_type == StreamItem && clicked_routeview) {
1643 clicked_routeview->build_underlay_menu(menu);
1646 /* When the region menu is opened, we setup the actions so that they look right
1649 sensitize_the_right_region_actions ();
1650 _last_region_menu_was_main = false;
1652 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1653 menu->popup (button, time);
1657 Editor::build_track_context_menu ()
1659 using namespace Menu_Helpers;
1661 MenuList& edit_items = track_context_menu.items();
1664 add_dstream_context_items (edit_items);
1665 return &track_context_menu;
1669 Editor::build_track_bus_context_menu ()
1671 using namespace Menu_Helpers;
1673 MenuList& edit_items = track_context_menu.items();
1676 add_bus_context_items (edit_items);
1677 return &track_context_menu;
1681 Editor::build_track_region_context_menu ()
1683 using namespace Menu_Helpers;
1684 MenuList& edit_items = track_region_context_menu.items();
1687 /* we've just cleared the track region context menu, so the menu that these
1688 two items were on will have disappeared; stop them dangling.
1690 region_edit_menu_split_item = 0;
1691 region_edit_menu_split_multichannel_item = 0;
1693 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1696 boost::shared_ptr<Track> tr;
1697 boost::shared_ptr<Playlist> pl;
1699 if ((tr = rtv->track())) {
1700 add_region_context_items (edit_items, tr);
1704 add_dstream_context_items (edit_items);
1706 return &track_region_context_menu;
1710 Editor::analyze_region_selection ()
1712 if (analysis_window == 0) {
1713 analysis_window = new AnalysisWindow();
1716 analysis_window->set_session(_session);
1718 analysis_window->show_all();
1721 analysis_window->set_regionmode();
1722 analysis_window->analyze();
1724 analysis_window->present();
1728 Editor::analyze_range_selection()
1730 if (analysis_window == 0) {
1731 analysis_window = new AnalysisWindow();
1734 analysis_window->set_session(_session);
1736 analysis_window->show_all();
1739 analysis_window->set_rangemode();
1740 analysis_window->analyze();
1742 analysis_window->present();
1746 Editor::build_track_selection_context_menu ()
1748 using namespace Menu_Helpers;
1749 MenuList& edit_items = track_selection_context_menu.items();
1750 edit_items.clear ();
1752 add_selection_context_items (edit_items);
1753 // edit_items.push_back (SeparatorElem());
1754 // add_dstream_context_items (edit_items);
1756 return &track_selection_context_menu;
1760 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1762 using namespace Menu_Helpers;
1764 /* OK, stick the region submenu at the top of the list, and then add
1768 RegionSelection rs = get_regions_from_selection_and_entered ();
1770 string::size_type pos = 0;
1771 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1773 /* we have to hack up the region name because "_" has a special
1774 meaning for menu titles.
1777 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1778 menu_item_name.replace (pos, 1, "__");
1782 if (_popup_region_menu_item == 0) {
1783 _popup_region_menu_item = new MenuItem (menu_item_name);
1784 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1785 _popup_region_menu_item->show ();
1787 _popup_region_menu_item->set_label (menu_item_name);
1790 /* No latering allowed in later is higher layering model */
1791 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1792 if (act && Config->get_layer_model() == LaterHigher) {
1793 act->set_sensitive (false);
1795 act->set_sensitive (true);
1798 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1800 edit_items.push_back (*_popup_region_menu_item);
1801 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1802 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1804 edit_items.push_back (SeparatorElem());
1807 /** Add context menu items relevant to selection ranges.
1808 * @param edit_items List to add the items to.
1811 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1813 using namespace Menu_Helpers;
1815 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1816 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1818 edit_items.push_back (SeparatorElem());
1819 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1821 edit_items.push_back (SeparatorElem());
1822 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1824 edit_items.push_back (SeparatorElem());
1826 edit_items.push_back (
1828 _("Move Range Start to Previous Region Boundary"),
1829 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1833 edit_items.push_back (
1835 _("Move Range Start to Next Region Boundary"),
1836 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1840 edit_items.push_back (
1842 _("Move Range End to Previous Region Boundary"),
1843 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1847 edit_items.push_back (
1849 _("Move Range End to Next Region Boundary"),
1850 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1854 edit_items.push_back (SeparatorElem());
1855 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1856 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1858 edit_items.push_back (SeparatorElem());
1859 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1861 edit_items.push_back (SeparatorElem());
1862 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1863 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1864 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1866 edit_items.push_back (SeparatorElem());
1867 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1869 edit_items.push_back (SeparatorElem());
1870 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1871 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1873 edit_items.push_back (SeparatorElem());
1874 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1875 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1876 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1877 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1878 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1879 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1880 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1886 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1888 using namespace Menu_Helpers;
1892 Menu *play_menu = manage (new Menu);
1893 MenuList& play_items = play_menu->items();
1894 play_menu->set_name ("ArdourContextMenu");
1896 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1897 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1898 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1899 play_items.push_back (SeparatorElem());
1900 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1902 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1906 Menu *select_menu = manage (new Menu);
1907 MenuList& select_items = select_menu->items();
1908 select_menu->set_name ("ArdourContextMenu");
1910 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1911 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1912 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1913 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1914 select_items.push_back (SeparatorElem());
1915 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1916 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1917 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
1918 select_items.push_back (SeparatorElem());
1919 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
1920 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
1921 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1922 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1923 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1924 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1925 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1927 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1931 Menu *cutnpaste_menu = manage (new Menu);
1932 MenuList& cutnpaste_items = cutnpaste_menu->items();
1933 cutnpaste_menu->set_name ("ArdourContextMenu");
1935 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1936 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1937 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1939 cutnpaste_items.push_back (SeparatorElem());
1941 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1942 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1944 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1946 /* Adding new material */
1948 edit_items.push_back (SeparatorElem());
1949 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1950 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1954 Menu *nudge_menu = manage (new Menu());
1955 MenuList& nudge_items = nudge_menu->items();
1956 nudge_menu->set_name ("ArdourContextMenu");
1958 edit_items.push_back (SeparatorElem());
1959 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1960 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1961 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1962 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1964 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1968 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1970 using namespace Menu_Helpers;
1974 Menu *play_menu = manage (new Menu);
1975 MenuList& play_items = play_menu->items();
1976 play_menu->set_name ("ArdourContextMenu");
1978 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1979 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1980 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1984 Menu *select_menu = manage (new Menu);
1985 MenuList& select_items = select_menu->items();
1986 select_menu->set_name ("ArdourContextMenu");
1988 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1989 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1990 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1991 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1992 select_items.push_back (SeparatorElem());
1993 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
1994 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
1995 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1996 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1998 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2002 Menu *cutnpaste_menu = manage (new Menu);
2003 MenuList& cutnpaste_items = cutnpaste_menu->items();
2004 cutnpaste_menu->set_name ("ArdourContextMenu");
2006 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2007 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2008 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2010 Menu *nudge_menu = manage (new Menu());
2011 MenuList& nudge_items = nudge_menu->items();
2012 nudge_menu->set_name ("ArdourContextMenu");
2014 edit_items.push_back (SeparatorElem());
2015 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2016 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2017 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2018 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2020 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2024 Editor::snap_type() const
2030 Editor::snap_mode() const
2036 Editor::set_snap_to (SnapType st)
2038 unsigned int snap_ind = (unsigned int)st;
2040 if (internal_editing()) {
2041 internal_snap_type = st;
2043 pre_internal_snap_type = st;
2048 if (snap_ind > snap_type_strings.size() - 1) {
2050 _snap_type = (SnapType)snap_ind;
2053 string str = snap_type_strings[snap_ind];
2055 if (str != snap_type_selector.get_text()) {
2056 snap_type_selector.set_text (str);
2061 switch (_snap_type) {
2062 case SnapToBeatDiv128:
2063 case SnapToBeatDiv64:
2064 case SnapToBeatDiv32:
2065 case SnapToBeatDiv28:
2066 case SnapToBeatDiv24:
2067 case SnapToBeatDiv20:
2068 case SnapToBeatDiv16:
2069 case SnapToBeatDiv14:
2070 case SnapToBeatDiv12:
2071 case SnapToBeatDiv10:
2072 case SnapToBeatDiv8:
2073 case SnapToBeatDiv7:
2074 case SnapToBeatDiv6:
2075 case SnapToBeatDiv5:
2076 case SnapToBeatDiv4:
2077 case SnapToBeatDiv3:
2078 case SnapToBeatDiv2: {
2079 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2080 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2082 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2083 current_bbt_points_begin, current_bbt_points_end);
2084 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2085 current_bbt_points_begin, current_bbt_points_end);
2086 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2090 case SnapToRegionStart:
2091 case SnapToRegionEnd:
2092 case SnapToRegionSync:
2093 case SnapToRegionBoundary:
2094 build_region_boundary_cache ();
2102 redisplay_tempo (false);
2104 SnapChanged (); /* EMIT SIGNAL */
2108 Editor::set_snap_mode (SnapMode mode)
2110 string str = snap_mode_strings[(int)mode];
2112 if (internal_editing()) {
2113 internal_snap_mode = mode;
2115 pre_internal_snap_mode = mode;
2120 if (str != snap_mode_selector.get_text ()) {
2121 snap_mode_selector.set_text (str);
2128 Editor::set_edit_point_preference (EditPoint ep, bool force)
2130 bool changed = (_edit_point != ep);
2133 if (Profile->get_mixbus())
2134 if (ep == EditAtSelectedMarker)
2135 ep = EditAtPlayhead;
2137 string str = edit_point_strings[(int)ep];
2138 if (str != edit_point_selector.get_text ()) {
2139 edit_point_selector.set_text (str);
2142 update_all_enter_cursors();
2144 if (!force && !changed) {
2148 const char* action=NULL;
2150 switch (_edit_point) {
2151 case EditAtPlayhead:
2152 action = "edit-at-playhead";
2154 case EditAtSelectedMarker:
2155 action = "edit-at-marker";
2158 action = "edit-at-mouse";
2162 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2164 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2168 bool in_track_canvas;
2170 if (!mouse_frame (foo, in_track_canvas)) {
2171 in_track_canvas = false;
2174 reset_canvas_action_sensitivity (in_track_canvas);
2180 Editor::set_state (const XMLNode& node, int version)
2182 const XMLProperty* prop;
2185 Tabbable::set_state (node, version);
2187 if (_session && (prop = node.property ("playhead"))) {
2189 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2191 playhead_cursor->set_position (pos);
2193 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2194 playhead_cursor->set_position (0);
2197 playhead_cursor->set_position (0);
2200 if ((prop = node.property ("mixer-width"))) {
2201 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2204 if ((prop = node.property ("zoom-focus"))) {
2205 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2208 if ((prop = node.property ("zoom"))) {
2209 /* older versions of ardour used floating point samples_per_pixel */
2210 double f = PBD::atof (prop->value());
2211 reset_zoom (llrintf (f));
2213 reset_zoom (samples_per_pixel);
2216 if ((prop = node.property ("visible-track-count"))) {
2217 set_visible_track_count (PBD::atoi (prop->value()));
2220 if ((prop = node.property ("snap-to"))) {
2221 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2224 if ((prop = node.property ("snap-mode"))) {
2225 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2228 if ((prop = node.property ("internal-snap-to"))) {
2229 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2232 if ((prop = node.property ("internal-snap-mode"))) {
2233 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2236 if ((prop = node.property ("pre-internal-snap-to"))) {
2237 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2240 if ((prop = node.property ("pre-internal-snap-mode"))) {
2241 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2244 if ((prop = node.property ("mouse-mode"))) {
2245 MouseMode m = str2mousemode(prop->value());
2246 set_mouse_mode (m, true);
2248 set_mouse_mode (MouseObject, true);
2251 if ((prop = node.property ("left-frame")) != 0) {
2253 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2257 reset_x_origin (pos);
2261 if ((prop = node.property ("y-origin")) != 0) {
2262 reset_y_origin (atof (prop->value ()));
2265 if ((prop = node.property ("join-object-range"))) {
2266 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2267 bool yn = string_is_affirmative (prop->value());
2269 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2270 tact->set_active (!yn);
2271 tact->set_active (yn);
2273 set_mouse_mode(mouse_mode, true);
2276 if ((prop = node.property ("edit-point"))) {
2277 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2280 if ((prop = node.property ("show-measures"))) {
2281 bool yn = string_is_affirmative (prop->value());
2282 _show_measures = yn;
2285 if ((prop = node.property ("follow-playhead"))) {
2286 bool yn = string_is_affirmative (prop->value());
2287 set_follow_playhead (yn);
2290 if ((prop = node.property ("stationary-playhead"))) {
2291 bool yn = string_is_affirmative (prop->value());
2292 set_stationary_playhead (yn);
2295 if ((prop = node.property ("region-list-sort-type"))) {
2296 RegionListSortType st;
2297 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2300 if ((prop = node.property ("show-editor-mixer"))) {
2302 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2305 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2306 bool yn = string_is_affirmative (prop->value());
2308 /* do it twice to force the change */
2310 tact->set_active (!yn);
2311 tact->set_active (yn);
2314 if ((prop = node.property ("show-editor-list"))) {
2316 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2319 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2320 bool yn = string_is_affirmative (prop->value());
2322 /* do it twice to force the change */
2324 tact->set_active (!yn);
2325 tact->set_active (yn);
2328 if ((prop = node.property (X_("editor-list-page")))) {
2329 _the_notebook.set_current_page (atoi (prop->value ()));
2332 if ((prop = node.property (X_("show-marker-lines")))) {
2333 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2335 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2336 bool yn = string_is_affirmative (prop->value ());
2338 tact->set_active (!yn);
2339 tact->set_active (yn);
2342 XMLNodeList children = node.children ();
2343 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2344 selection->set_state (**i, Stateful::current_state_version);
2345 _regions->set_state (**i);
2348 if ((prop = node.property ("maximised"))) {
2349 bool yn = string_is_affirmative (prop->value());
2350 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2352 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2353 bool fs = tact && tact->get_active();
2355 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2359 if ((prop = node.property ("nudge-clock-value"))) {
2361 sscanf (prop->value().c_str(), "%" PRId64, &f);
2362 nudge_clock->set (f);
2364 nudge_clock->set_mode (AudioClock::Timecode);
2365 nudge_clock->set (_session->frame_rate() * 5, true);
2370 * Not all properties may have been in XML, but
2371 * those that are linked to a private variable may need changing
2376 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2378 yn = _show_measures;
2379 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2380 /* do it twice to force the change */
2381 tact->set_active (!yn);
2382 tact->set_active (yn);
2385 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2386 yn = _follow_playhead;
2388 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2389 if (tact->get_active() != yn) {
2390 tact->set_active (yn);
2394 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2395 yn = _stationary_playhead;
2397 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2398 if (tact->get_active() != yn) {
2399 tact->set_active (yn);
2408 Editor::get_state ()
2410 XMLNode* node = new XMLNode (X_("Editor"));
2413 id().print (buf, sizeof (buf));
2414 node->add_property ("id", buf);
2416 node->add_child_nocopy (Tabbable::get_state());
2418 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2419 node->add_property("edit-horizontal-pane-pos", string(buf));
2420 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2421 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2422 node->add_property("edit-vertical-pane-pos", string(buf));
2424 maybe_add_mixer_strip_width (*node);
2426 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2428 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2429 node->add_property ("zoom", buf);
2430 node->add_property ("snap-to", enum_2_string (_snap_type));
2431 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2432 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2433 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2434 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2435 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2436 node->add_property ("edit-point", enum_2_string (_edit_point));
2437 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2438 node->add_property ("visible-track-count", buf);
2440 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2441 node->add_property ("playhead", buf);
2442 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2443 node->add_property ("left-frame", buf);
2444 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2445 node->add_property ("y-origin", buf);
2447 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2448 node->add_property ("maximised", _maximised ? "yes" : "no");
2449 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2450 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2451 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2452 node->add_property ("mouse-mode", enum2str(mouse_mode));
2453 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2455 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2457 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2458 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2461 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2463 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2464 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2467 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2468 node->add_property (X_("editor-list-page"), buf);
2470 if (button_bindings) {
2471 XMLNode* bb = new XMLNode (X_("Buttons"));
2472 button_bindings->save (*bb);
2473 node->add_child_nocopy (*bb);
2476 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2478 node->add_child_nocopy (selection->get_state ());
2479 node->add_child_nocopy (_regions->get_state ());
2481 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2482 node->add_property ("nudge-clock-value", buf);
2487 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2488 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2490 * @return pair: TimeAxisView that y is over, layer index.
2492 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2493 * in stacked or expanded region display mode, otherwise 0.
2495 std::pair<TimeAxisView *, double>
2496 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2498 if (!trackview_relative_offset) {
2499 y -= _trackview_group->canvas_origin().y;
2503 return std::make_pair ( (TimeAxisView *) 0, 0);
2506 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2508 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2515 return std::make_pair ( (TimeAxisView *) 0, 0);
2518 /** Snap a position to the grid, if appropriate, taking into account current
2519 * grid settings and also the state of any snap modifier keys that may be pressed.
2520 * @param start Position to snap.
2521 * @param event Event to get current key modifier information from, or 0.
2524 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2526 if (!_session || !event) {
2530 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2531 if (_snap_mode == SnapOff) {
2532 snap_to_internal (start, direction, for_mark);
2535 if (_snap_mode != SnapOff) {
2536 snap_to_internal (start, direction, for_mark);
2537 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2538 /* SnapOff, but we pressed the snap_delta modifier */
2539 snap_to_internal (start, direction, for_mark);
2545 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2547 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2551 snap_to_internal (start, direction, for_mark, ensure_snap);
2555 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2557 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2558 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2560 switch (_snap_type) {
2561 case SnapToTimecodeFrame:
2562 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2563 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2564 /* start is already on a whole timecode frame, do nothing */
2565 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2566 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2568 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2572 case SnapToTimecodeSeconds:
2573 if (_session->config.get_timecode_offset_negative()) {
2574 start += _session->config.get_timecode_offset ();
2576 start -= _session->config.get_timecode_offset ();
2578 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2579 (start % one_timecode_second == 0)) {
2580 /* start is already on a whole second, do nothing */
2581 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2582 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2584 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2587 if (_session->config.get_timecode_offset_negative()) {
2588 start -= _session->config.get_timecode_offset ();
2590 start += _session->config.get_timecode_offset ();
2594 case SnapToTimecodeMinutes:
2595 if (_session->config.get_timecode_offset_negative()) {
2596 start += _session->config.get_timecode_offset ();
2598 start -= _session->config.get_timecode_offset ();
2600 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2601 (start % one_timecode_minute == 0)) {
2602 /* start is already on a whole minute, do nothing */
2603 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2604 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2606 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2608 if (_session->config.get_timecode_offset_negative()) {
2609 start -= _session->config.get_timecode_offset ();
2611 start += _session->config.get_timecode_offset ();
2615 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2616 abort(); /*NOTREACHED*/
2621 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2623 const framepos_t one_second = _session->frame_rate();
2624 const framepos_t one_minute = _session->frame_rate() * 60;
2625 framepos_t presnap = start;
2629 switch (_snap_type) {
2630 case SnapToTimecodeFrame:
2631 case SnapToTimecodeSeconds:
2632 case SnapToTimecodeMinutes:
2633 return timecode_snap_to_internal (start, direction, for_mark);
2636 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2637 start % (one_second/75) == 0) {
2638 /* start is already on a whole CD frame, do nothing */
2639 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2640 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2642 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2647 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2648 start % one_second == 0) {
2649 /* start is already on a whole second, do nothing */
2650 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2651 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2653 start = (framepos_t) floor ((double) start / one_second) * one_second;
2658 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2659 start % one_minute == 0) {
2660 /* start is already on a whole minute, do nothing */
2661 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2662 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2664 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2669 start = _session->tempo_map().round_to_bar (start, direction);
2673 start = _session->tempo_map().round_to_beat (start, direction);
2676 case SnapToBeatDiv128:
2677 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2679 case SnapToBeatDiv64:
2680 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2682 case SnapToBeatDiv32:
2683 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2685 case SnapToBeatDiv28:
2686 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2688 case SnapToBeatDiv24:
2689 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2691 case SnapToBeatDiv20:
2692 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2694 case SnapToBeatDiv16:
2695 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2697 case SnapToBeatDiv14:
2698 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2700 case SnapToBeatDiv12:
2701 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2703 case SnapToBeatDiv10:
2704 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2706 case SnapToBeatDiv8:
2707 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2709 case SnapToBeatDiv7:
2710 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2712 case SnapToBeatDiv6:
2713 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2715 case SnapToBeatDiv5:
2716 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2718 case SnapToBeatDiv4:
2719 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2721 case SnapToBeatDiv3:
2722 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2724 case SnapToBeatDiv2:
2725 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2733 _session->locations()->marks_either_side (start, before, after);
2735 if (before == max_framepos && after == max_framepos) {
2736 /* No marks to snap to, so just don't snap */
2738 } else if (before == max_framepos) {
2740 } else if (after == max_framepos) {
2742 } else if (before != max_framepos && after != max_framepos) {
2743 /* have before and after */
2744 if ((start - before) < (after - start)) {
2753 case SnapToRegionStart:
2754 case SnapToRegionEnd:
2755 case SnapToRegionSync:
2756 case SnapToRegionBoundary:
2757 if (!region_boundary_cache.empty()) {
2759 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2760 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2762 if (direction > 0) {
2763 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2765 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2768 if (next != region_boundary_cache.begin ()) {
2773 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2774 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2776 if (start > (p + n) / 2) {
2785 switch (_snap_mode) {
2795 if (presnap > start) {
2796 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2800 } else if (presnap < start) {
2801 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2807 /* handled at entry */
2815 Editor::setup_toolbar ()
2817 HBox* mode_box = manage(new HBox);
2818 mode_box->set_border_width (2);
2819 mode_box->set_spacing(2);
2821 HBox* mouse_mode_box = manage (new HBox);
2822 HBox* mouse_mode_hbox = manage (new HBox);
2823 VBox* mouse_mode_vbox = manage (new VBox);
2824 Alignment* mouse_mode_align = manage (new Alignment);
2826 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2827 mouse_mode_size_group->add_widget (smart_mode_button);
2828 mouse_mode_size_group->add_widget (mouse_move_button);
2829 mouse_mode_size_group->add_widget (mouse_cut_button);
2830 mouse_mode_size_group->add_widget (mouse_select_button);
2831 mouse_mode_size_group->add_widget (mouse_timefx_button);
2832 mouse_mode_size_group->add_widget (mouse_audition_button);
2833 mouse_mode_size_group->add_widget (mouse_draw_button);
2834 mouse_mode_size_group->add_widget (mouse_content_button);
2836 mouse_mode_size_group->add_widget (zoom_in_button);
2837 mouse_mode_size_group->add_widget (zoom_out_button);
2838 mouse_mode_size_group->add_widget (zoom_preset_selector);
2839 mouse_mode_size_group->add_widget (zoom_out_full_button);
2840 mouse_mode_size_group->add_widget (zoom_focus_selector);
2842 mouse_mode_size_group->add_widget (tav_shrink_button);
2843 mouse_mode_size_group->add_widget (tav_expand_button);
2844 mouse_mode_size_group->add_widget (visible_tracks_selector);
2846 mouse_mode_size_group->add_widget (snap_type_selector);
2847 mouse_mode_size_group->add_widget (snap_mode_selector);
2849 mouse_mode_size_group->add_widget (edit_point_selector);
2850 mouse_mode_size_group->add_widget (edit_mode_selector);
2852 mouse_mode_size_group->add_widget (*nudge_clock);
2853 mouse_mode_size_group->add_widget (nudge_forward_button);
2854 mouse_mode_size_group->add_widget (nudge_backward_button);
2856 mouse_mode_hbox->set_spacing (2);
2858 if (!ARDOUR::Profile->get_trx()) {
2859 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2862 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2863 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2865 if (!ARDOUR::Profile->get_mixbus()) {
2866 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2869 if (!ARDOUR::Profile->get_trx()) {
2870 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2871 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2872 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2873 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2876 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2878 mouse_mode_align->add (*mouse_mode_vbox);
2879 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2881 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2883 edit_mode_selector.set_name ("mouse mode button");
2885 if (!ARDOUR::Profile->get_trx()) {
2886 mode_box->pack_start (edit_mode_selector, false, false);
2889 mode_box->pack_start (*mouse_mode_box, false, false);
2893 _zoom_box.set_spacing (2);
2894 _zoom_box.set_border_width (2);
2898 zoom_preset_selector.set_name ("zoom button");
2899 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2900 zoom_preset_selector.set_size_request (42, -1);
2902 zoom_in_button.set_name ("zoom button");
2903 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
2904 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2905 zoom_in_button.set_related_action (act);
2907 zoom_out_button.set_name ("zoom button");
2908 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
2909 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2910 zoom_out_button.set_related_action (act);
2912 zoom_out_full_button.set_name ("zoom button");
2913 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
2914 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2915 zoom_out_full_button.set_related_action (act);
2917 zoom_focus_selector.set_name ("zoom button");
2919 if (ARDOUR::Profile->get_mixbus()) {
2920 _zoom_box.pack_start (zoom_preset_selector, false, false);
2921 } else if (ARDOUR::Profile->get_trx()) {
2922 mode_box->pack_start (zoom_out_button, false, false);
2923 mode_box->pack_start (zoom_in_button, false, false);
2925 _zoom_box.pack_start (zoom_out_button, false, false);
2926 _zoom_box.pack_start (zoom_in_button, false, false);
2927 _zoom_box.pack_start (zoom_out_full_button, false, false);
2928 _zoom_box.pack_start (zoom_focus_selector, false, false);
2931 /* Track zoom buttons */
2932 visible_tracks_selector.set_name ("zoom button");
2933 if (Profile->get_mixbus()) {
2934 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2935 visible_tracks_selector.set_size_request (42, -1);
2937 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2940 tav_expand_button.set_name ("zoom button");
2941 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
2942 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2943 tav_expand_button.set_related_action (act);
2945 tav_shrink_button.set_name ("zoom button");
2946 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
2947 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2948 tav_shrink_button.set_related_action (act);
2950 if (ARDOUR::Profile->get_mixbus()) {
2951 _zoom_box.pack_start (visible_tracks_selector);
2952 } else if (ARDOUR::Profile->get_trx()) {
2953 _zoom_box.pack_start (tav_shrink_button);
2954 _zoom_box.pack_start (tav_expand_button);
2956 _zoom_box.pack_start (visible_tracks_selector);
2957 _zoom_box.pack_start (tav_shrink_button);
2958 _zoom_box.pack_start (tav_expand_button);
2961 snap_box.set_spacing (2);
2962 snap_box.set_border_width (2);
2964 snap_type_selector.set_name ("mouse mode button");
2966 snap_mode_selector.set_name ("mouse mode button");
2968 edit_point_selector.set_name ("mouse mode button");
2970 snap_box.pack_start (snap_mode_selector, false, false);
2971 snap_box.pack_start (snap_type_selector, false, false);
2972 snap_box.pack_start (edit_point_selector, false, false);
2976 HBox *nudge_box = manage (new HBox);
2977 nudge_box->set_spacing (2);
2978 nudge_box->set_border_width (2);
2980 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2981 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2983 nudge_box->pack_start (nudge_backward_button, false, false);
2984 nudge_box->pack_start (nudge_forward_button, false, false);
2985 nudge_box->pack_start (*nudge_clock, false, false);
2988 /* Pack everything in... */
2990 HBox* hbox = manage (new HBox);
2991 hbox->set_spacing(2);
2993 toolbar_hbox.set_spacing (2);
2994 toolbar_hbox.set_border_width (1);
2996 toolbar_hbox.pack_start (*mode_box, false, false);
2997 if (!ARDOUR::Profile->get_trx()) {
2998 toolbar_hbox.pack_start (_zoom_box, false, false);
2999 toolbar_hbox.pack_start (*hbox, false, false);
3002 if (!ARDOUR::Profile->get_trx()) {
3003 hbox->pack_start (snap_box, false, false);
3004 hbox->pack_start (*nudge_box, false, false);
3009 toolbar_base.set_name ("ToolBarBase");
3010 toolbar_base.add (toolbar_hbox);
3012 _toolbar_viewport.add (toolbar_base);
3013 /* stick to the required height but allow width to vary if there's not enough room */
3014 _toolbar_viewport.set_size_request (1, -1);
3016 toolbar_frame.set_shadow_type (SHADOW_OUT);
3017 toolbar_frame.set_name ("BaseFrame");
3018 toolbar_frame.add (_toolbar_viewport);
3022 Editor::build_edit_point_menu ()
3024 using namespace Menu_Helpers;
3026 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3027 if(!Profile->get_mixbus())
3028 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3029 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3031 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3035 Editor::build_edit_mode_menu ()
3037 using namespace Menu_Helpers;
3039 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3040 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3041 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3042 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3044 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3048 Editor::build_snap_mode_menu ()
3050 using namespace Menu_Helpers;
3052 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3053 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3054 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3056 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3060 Editor::build_snap_type_menu ()
3062 using namespace Menu_Helpers;
3064 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3065 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3066 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3067 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3068 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3069 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3070 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3071 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3072 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3073 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3074 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3075 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3076 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3077 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3078 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3079 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3080 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3081 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3082 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3083 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3084 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3085 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3086 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3087 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3088 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3089 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3090 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3091 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3092 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3093 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3095 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3100 Editor::setup_tooltips ()
3102 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3103 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3104 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3105 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3106 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3107 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3108 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3109 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3110 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3111 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3112 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3113 set_tooltip (zoom_in_button, _("Zoom In"));
3114 set_tooltip (zoom_out_button, _("Zoom Out"));
3115 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3116 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3117 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3118 set_tooltip (tav_expand_button, _("Expand Tracks"));
3119 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3120 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3121 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3122 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3123 set_tooltip (edit_point_selector, _("Edit Point"));
3124 set_tooltip (edit_mode_selector, _("Edit Mode"));
3125 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3129 Editor::convert_drop_to_paths (
3130 vector<string>& paths,
3131 const RefPtr<Gdk::DragContext>& /*context*/,
3134 const SelectionData& data,
3138 if (_session == 0) {
3142 vector<string> uris = data.get_uris();
3146 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3147 are actually URI lists. So do it by hand.
3150 if (data.get_target() != "text/plain") {
3154 /* Parse the "uri-list" format that Nautilus provides,
3155 where each pathname is delimited by \r\n.
3157 THERE MAY BE NO NULL TERMINATING CHAR!!!
3160 string txt = data.get_text();
3164 p = (char *) malloc (txt.length() + 1);
3165 txt.copy (p, txt.length(), 0);
3166 p[txt.length()] = '\0';
3172 while (g_ascii_isspace (*p))
3176 while (*q && (*q != '\n') && (*q != '\r')) {
3183 while (q > p && g_ascii_isspace (*q))
3188 uris.push_back (string (p, q - p + 1));
3192 p = strchr (p, '\n');
3204 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3205 if ((*i).substr (0,7) == "file://") {
3206 paths.push_back (Glib::filename_from_uri (*i));
3214 Editor::new_tempo_section ()
3219 Editor::map_transport_state ()
3221 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3223 if (_session && _session->transport_stopped()) {
3224 have_pending_keyboard_selection = false;
3227 update_loop_range_view ();
3233 Editor::begin_selection_op_history ()
3235 selection_op_cmd_depth = 0;
3236 selection_op_history_it = 0;
3238 while(!selection_op_history.empty()) {
3239 delete selection_op_history.front();
3240 selection_op_history.pop_front();
3243 selection_undo_action->set_sensitive (false);
3244 selection_redo_action->set_sensitive (false);
3245 selection_op_history.push_front (&_selection_memento->get_state ());
3249 Editor::begin_reversible_selection_op (string name)
3252 //cerr << name << endl;
3253 /* begin/commit pairs can be nested */
3254 selection_op_cmd_depth++;
3259 Editor::commit_reversible_selection_op ()
3262 if (selection_op_cmd_depth == 1) {
3264 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3266 The user has undone some selection ops and then made a new one,
3267 making anything earlier in the list invalid.
3270 list<XMLNode *>::iterator it = selection_op_history.begin();
3271 list<XMLNode *>::iterator e_it = it;
3272 advance (e_it, selection_op_history_it);
3274 for ( ; it != e_it; ++it) {
3277 selection_op_history.erase (selection_op_history.begin(), e_it);
3280 selection_op_history.push_front (&_selection_memento->get_state ());
3281 selection_op_history_it = 0;
3283 selection_undo_action->set_sensitive (true);
3284 selection_redo_action->set_sensitive (false);
3287 if (selection_op_cmd_depth > 0) {
3288 selection_op_cmd_depth--;
3294 Editor::undo_selection_op ()
3297 selection_op_history_it++;
3299 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3300 if (n == selection_op_history_it) {
3301 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3302 selection_redo_action->set_sensitive (true);
3306 /* is there an earlier entry? */
3307 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3308 selection_undo_action->set_sensitive (false);
3314 Editor::redo_selection_op ()
3317 if (selection_op_history_it > 0) {
3318 selection_op_history_it--;
3321 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3322 if (n == selection_op_history_it) {
3323 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3324 selection_undo_action->set_sensitive (true);
3329 if (selection_op_history_it == 0) {
3330 selection_redo_action->set_sensitive (false);
3336 Editor::begin_reversible_command (string name)
3339 before.push_back (&_selection_memento->get_state ());
3340 _session->begin_reversible_command (name);
3345 Editor::begin_reversible_command (GQuark q)
3348 before.push_back (&_selection_memento->get_state ());
3349 _session->begin_reversible_command (q);
3354 Editor::abort_reversible_command ()
3357 while(!before.empty()) {
3358 delete before.front();
3361 _session->abort_reversible_command ();
3366 Editor::commit_reversible_command ()
3369 if (before.size() == 1) {
3370 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3371 redo_action->set_sensitive(false);
3372 undo_action->set_sensitive(true);
3373 begin_selection_op_history ();
3376 if (before.empty()) {
3377 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3382 _session->commit_reversible_command ();
3387 Editor::history_changed ()
3391 if (undo_action && _session) {
3392 if (_session->undo_depth() == 0) {
3393 label = S_("Command|Undo");
3395 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3397 undo_action->property_label() = label;
3400 if (redo_action && _session) {
3401 if (_session->redo_depth() == 0) {
3403 redo_action->set_sensitive (false);
3405 label = string_compose(_("Redo (%1)"), _session->next_redo());
3406 redo_action->set_sensitive (true);
3408 redo_action->property_label() = label;
3413 Editor::duplicate_range (bool with_dialog)
3417 RegionSelection rs = get_regions_from_selection_and_entered ();
3419 if ( selection->time.length() == 0 && rs.empty()) {
3425 ArdourDialog win (_("Duplicate"));
3426 Label label (_("Number of duplications:"));
3427 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3428 SpinButton spinner (adjustment, 0.0, 1);
3431 win.get_vbox()->set_spacing (12);
3432 win.get_vbox()->pack_start (hbox);
3433 hbox.set_border_width (6);
3434 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3436 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3437 place, visually. so do this by hand.
3440 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3441 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3442 spinner.grab_focus();
3448 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3449 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3450 win.set_default_response (RESPONSE_ACCEPT);
3452 spinner.grab_focus ();
3454 switch (win.run ()) {
3455 case RESPONSE_ACCEPT:
3461 times = adjustment.get_value();
3464 if ((current_mouse_mode() == Editing::MouseRange)) {
3465 if (selection->time.length()) {
3466 duplicate_selection (times);
3468 } else if (get_smart_mode()) {
3469 if (selection->time.length()) {
3470 duplicate_selection (times);
3472 duplicate_some_regions (rs, times);
3474 duplicate_some_regions (rs, times);
3479 Editor::set_edit_mode (EditMode m)
3481 Config->set_edit_mode (m);
3485 Editor::cycle_edit_mode ()
3487 switch (Config->get_edit_mode()) {
3489 if (Profile->get_sae()) {
3490 Config->set_edit_mode (Lock);
3492 Config->set_edit_mode (Ripple);
3497 Config->set_edit_mode (Lock);
3500 Config->set_edit_mode (Slide);
3506 Editor::edit_mode_selection_done ( EditMode m )
3508 Config->set_edit_mode ( m );
3512 Editor::snap_type_selection_done (SnapType snaptype)
3514 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3516 ract->set_active ();
3521 Editor::snap_mode_selection_done (SnapMode mode)
3523 RefPtr<RadioAction> ract = snap_mode_action (mode);
3526 ract->set_active (true);
3531 Editor::cycle_edit_point (bool with_marker)
3533 if(Profile->get_mixbus())
3534 with_marker = false;
3536 switch (_edit_point) {
3538 set_edit_point_preference (EditAtPlayhead);
3540 case EditAtPlayhead:
3542 set_edit_point_preference (EditAtSelectedMarker);
3544 set_edit_point_preference (EditAtMouse);
3547 case EditAtSelectedMarker:
3548 set_edit_point_preference (EditAtMouse);
3554 Editor::edit_point_selection_done (EditPoint ep)
3556 set_edit_point_preference ( ep );
3560 Editor::build_zoom_focus_menu ()
3562 using namespace Menu_Helpers;
3564 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3565 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3566 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3567 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3568 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3569 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3571 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3575 Editor::zoom_focus_selection_done ( ZoomFocus f )
3577 RefPtr<RadioAction> ract = zoom_focus_action (f);
3579 ract->set_active ();
3584 Editor::build_track_count_menu ()
3586 using namespace Menu_Helpers;
3588 if (!Profile->get_mixbus()) {
3589 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3590 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3591 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3592 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3593 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3594 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3595 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3596 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3597 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3598 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3599 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3600 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3601 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3603 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3604 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3605 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3606 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3607 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3608 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3609 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3610 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3611 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3612 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3614 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3615 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3616 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3617 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3618 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3619 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3620 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3621 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3622 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3623 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3624 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3629 Editor::set_zoom_preset (int64_t ms)
3632 temporal_zoom_session();
3636 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3637 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3641 Editor::set_visible_track_count (int32_t n)
3643 _visible_track_count = n;
3645 /* if the canvas hasn't really been allocated any size yet, just
3646 record the desired number of visible tracks and return. when canvas
3647 allocation happens, we will get called again and then we can do the
3651 if (_visible_canvas_height <= 1) {
3657 DisplaySuspender ds;
3659 if (_visible_track_count > 0) {
3660 h = trackviews_height() / _visible_track_count;
3661 std::ostringstream s;
3662 s << _visible_track_count;
3664 } else if (_visible_track_count == 0) {
3666 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3667 if ((*i)->marked_for_display()) {
3671 h = trackviews_height() / n;
3674 /* negative value means that the visible track count has
3675 been overridden by explicit track height changes.
3677 visible_tracks_selector.set_text (X_("*"));
3681 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3682 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3685 if (str != visible_tracks_selector.get_text()) {
3686 visible_tracks_selector.set_text (str);
3691 Editor::override_visible_track_count ()
3693 _visible_track_count = -1;
3694 visible_tracks_selector.set_text ( _("*") );
3698 Editor::edit_controls_button_release (GdkEventButton* ev)
3700 if (Keyboard::is_context_menu_event (ev)) {
3701 ARDOUR_UI::instance()->add_route (current_toplevel());
3702 } else if (ev->button == 1) {
3703 selection->clear_tracks ();
3710 Editor::mouse_select_button_release (GdkEventButton* ev)
3712 /* this handles just right-clicks */
3714 if (ev->button != 3) {
3722 Editor::set_zoom_focus (ZoomFocus f)
3724 string str = zoom_focus_strings[(int)f];
3726 if (str != zoom_focus_selector.get_text()) {
3727 zoom_focus_selector.set_text (str);
3730 if (zoom_focus != f) {
3737 Editor::cycle_zoom_focus ()
3739 switch (zoom_focus) {
3741 set_zoom_focus (ZoomFocusRight);
3743 case ZoomFocusRight:
3744 set_zoom_focus (ZoomFocusCenter);
3746 case ZoomFocusCenter:
3747 set_zoom_focus (ZoomFocusPlayhead);
3749 case ZoomFocusPlayhead:
3750 set_zoom_focus (ZoomFocusMouse);
3752 case ZoomFocusMouse:
3753 set_zoom_focus (ZoomFocusEdit);
3756 set_zoom_focus (ZoomFocusLeft);
3762 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3764 /* recover or initialize pane positions. do this here rather than earlier because
3765 we don't want the positions to change the child allocations, which they seem to do.
3771 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3780 XMLNode* geometry = find_named_node (*node, "geometry");
3782 if (which == static_cast<Paned*> (&edit_pane)) {
3784 if (done & Horizontal) {
3788 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3789 _notebook_shrunk = string_is_affirmative (prop->value ());
3792 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3793 /* initial allocation is 90% to canvas, 10% to notebook */
3794 pos = (int) floor (alloc.get_width() * 0.90f);
3795 snprintf (buf, sizeof(buf), "%d", pos);
3797 pos = atoi (prop->value());
3800 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3801 edit_pane.set_position (pos);
3804 done = (Pane) (done | Horizontal);
3806 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3808 if (done & Vertical) {
3812 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3813 /* initial allocation is 90% to canvas, 10% to summary */
3814 pos = (int) floor (alloc.get_height() * 0.90f);
3815 snprintf (buf, sizeof(buf), "%d", pos);
3818 pos = atoi (prop->value());
3821 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3822 editor_summary_pane.set_position (pos);
3825 done = (Pane) (done | Vertical);
3830 Editor::set_show_measures (bool yn)
3832 if (_show_measures != yn) {
3835 if ((_show_measures = yn) == true) {
3837 tempo_lines->show();
3840 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3841 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3843 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3844 draw_measures (begin, end);
3852 Editor::toggle_follow_playhead ()
3854 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3856 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3857 set_follow_playhead (tact->get_active());
3861 /** @param yn true to follow playhead, otherwise false.
3862 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3865 Editor::set_follow_playhead (bool yn, bool catch_up)
3867 if (_follow_playhead != yn) {
3868 if ((_follow_playhead = yn) == true && catch_up) {
3870 reset_x_origin_to_follow_playhead ();
3877 Editor::toggle_stationary_playhead ()
3879 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3881 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3882 set_stationary_playhead (tact->get_active());
3887 Editor::set_stationary_playhead (bool yn)
3889 if (_stationary_playhead != yn) {
3890 if ((_stationary_playhead = yn) == true) {
3892 // FIXME need a 3.0 equivalent of this 2.X call
3893 // update_current_screen ();
3900 Editor::playlist_selector () const
3902 return *_playlist_selector;
3906 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
3908 if (paste_count == 0) {
3909 /* don't bother calculating an offset that will be zero anyway */
3913 /* calculate basic unsnapped multi-paste offset */
3914 framecnt_t offset = paste_count * duration;
3916 /* snap offset so pos + offset is aligned to the grid */
3917 framepos_t offset_pos = pos + offset;
3918 snap_to(offset_pos, RoundUpMaybe);
3919 offset = offset_pos - pos;
3925 Editor::get_grid_beat_divisions(framepos_t position)
3927 switch (_snap_type) {
3928 case SnapToBeatDiv128: return 128;
3929 case SnapToBeatDiv64: return 64;
3930 case SnapToBeatDiv32: return 32;
3931 case SnapToBeatDiv28: return 28;
3932 case SnapToBeatDiv24: return 24;
3933 case SnapToBeatDiv20: return 20;
3934 case SnapToBeatDiv16: return 16;
3935 case SnapToBeatDiv14: return 14;
3936 case SnapToBeatDiv12: return 12;
3937 case SnapToBeatDiv10: return 10;
3938 case SnapToBeatDiv8: return 8;
3939 case SnapToBeatDiv7: return 7;
3940 case SnapToBeatDiv6: return 6;
3941 case SnapToBeatDiv5: return 5;
3942 case SnapToBeatDiv4: return 4;
3943 case SnapToBeatDiv3: return 3;
3944 case SnapToBeatDiv2: return 2;
3951 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3955 const unsigned divisions = get_grid_beat_divisions(position);
3957 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
3960 switch (_snap_type) {
3962 return Evoral::Beats(1.0);
3965 return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
3973 return Evoral::Beats();
3977 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3981 ret = nudge_clock->current_duration (pos);
3982 next = ret + 1; /* XXXX fix me */
3988 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3990 ArdourDialog dialog (_("Playlist Deletion"));
3991 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3992 "If it is kept, its audio files will not be cleaned.\n"
3993 "If it is deleted, audio files used by it alone will be cleaned."),
3996 dialog.set_position (WIN_POS_CENTER);
3997 dialog.get_vbox()->pack_start (label);
4001 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4002 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4003 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4004 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4005 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4007 // by default gtk uses the left most button
4008 keep->grab_focus ();
4010 switch (dialog.run ()) {
4012 /* keep this and all remaining ones */
4017 /* delete this and all others */
4021 case RESPONSE_ACCEPT:
4022 /* delete the playlist */
4026 case RESPONSE_REJECT:
4027 /* keep the playlist */
4039 Editor::audio_region_selection_covers (framepos_t where)
4041 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4042 if ((*a)->region()->covers (where)) {
4051 Editor::prepare_for_cleanup ()
4053 cut_buffer->clear_regions ();
4054 cut_buffer->clear_playlists ();
4056 selection->clear_regions ();
4057 selection->clear_playlists ();
4059 _regions->suspend_redisplay ();
4063 Editor::finish_cleanup ()
4065 _regions->resume_redisplay ();
4069 Editor::transport_loop_location()
4072 return _session->locations()->auto_loop_location();
4079 Editor::transport_punch_location()
4082 return _session->locations()->auto_punch_location();
4089 Editor::control_layout_scroll (GdkEventScroll* ev)
4091 /* Just forward to the normal canvas scroll method. The coordinate
4092 systems are different but since the canvas is always larger than the
4093 track headers, and aligned with the trackview area, this will work.
4095 In the not too distant future this layout is going away anyway and
4096 headers will be on the canvas.
4098 return canvas_scroll_event (ev, false);
4102 Editor::session_state_saved (string)
4105 _snapshots->redisplay ();
4109 Editor::maximise_editing_space ()
4115 Gtk::Window* toplevel = current_toplevel();
4118 toplevel->fullscreen ();
4124 Editor::restore_editing_space ()
4130 Gtk::Window* toplevel = current_toplevel();
4133 toplevel->unfullscreen();
4139 * Make new playlists for a given track and also any others that belong
4140 * to the same active route group with the `select' property.
4145 Editor::new_playlists (TimeAxisView* v)
4147 begin_reversible_command (_("new playlists"));
4148 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4149 _session->playlists->get (playlists);
4150 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4151 commit_reversible_command ();
4155 * Use a copy of the current playlist for a given track and also any others that belong
4156 * to the same active route group with the `select' property.
4161 Editor::copy_playlists (TimeAxisView* v)
4163 begin_reversible_command (_("copy playlists"));
4164 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4165 _session->playlists->get (playlists);
4166 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4167 commit_reversible_command ();
4170 /** Clear the current playlist for a given track and also any others that belong
4171 * to the same active route group with the `select' property.
4176 Editor::clear_playlists (TimeAxisView* v)
4178 begin_reversible_command (_("clear playlists"));
4179 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4180 _session->playlists->get (playlists);
4181 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4182 commit_reversible_command ();
4186 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4188 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4192 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4194 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4198 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4200 atv.clear_playlist ();
4204 Editor::get_y_origin () const
4206 return vertical_adjustment.get_value ();
4209 /** Queue up a change to the viewport x origin.
4210 * @param frame New x origin.
4213 Editor::reset_x_origin (framepos_t frame)
4215 pending_visual_change.add (VisualChange::TimeOrigin);
4216 pending_visual_change.time_origin = frame;
4217 ensure_visual_change_idle_handler ();
4221 Editor::reset_y_origin (double y)
4223 pending_visual_change.add (VisualChange::YOrigin);
4224 pending_visual_change.y_origin = y;
4225 ensure_visual_change_idle_handler ();
4229 Editor::reset_zoom (framecnt_t spp)
4231 if (spp == samples_per_pixel) {
4235 pending_visual_change.add (VisualChange::ZoomLevel);
4236 pending_visual_change.samples_per_pixel = spp;
4237 ensure_visual_change_idle_handler ();
4241 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4243 reset_x_origin (frame);
4246 if (!no_save_visual) {
4247 undo_visual_stack.push_back (current_visual_state(false));
4251 Editor::VisualState::VisualState (bool with_tracks)
4252 : gui_state (with_tracks ? new GUIObjectState : 0)
4256 Editor::VisualState::~VisualState ()
4261 Editor::VisualState*
4262 Editor::current_visual_state (bool with_tracks)
4264 VisualState* vs = new VisualState (with_tracks);
4265 vs->y_position = vertical_adjustment.get_value();
4266 vs->samples_per_pixel = samples_per_pixel;
4267 vs->leftmost_frame = leftmost_frame;
4268 vs->zoom_focus = zoom_focus;
4271 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4278 Editor::undo_visual_state ()
4280 if (undo_visual_stack.empty()) {
4284 VisualState* vs = undo_visual_stack.back();
4285 undo_visual_stack.pop_back();
4288 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4291 use_visual_state (*vs);
4296 Editor::redo_visual_state ()
4298 if (redo_visual_stack.empty()) {
4302 VisualState* vs = redo_visual_stack.back();
4303 redo_visual_stack.pop_back();
4305 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4306 // why do we check here?
4307 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4310 use_visual_state (*vs);
4315 Editor::swap_visual_state ()
4317 if (undo_visual_stack.empty()) {
4318 redo_visual_state ();
4320 undo_visual_state ();
4325 Editor::use_visual_state (VisualState& vs)
4327 PBD::Unwinder<bool> nsv (no_save_visual, true);
4328 DisplaySuspender ds;
4330 vertical_adjustment.set_value (vs.y_position);
4332 set_zoom_focus (vs.zoom_focus);
4333 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4336 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4338 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4339 (*i)->clear_property_cache();
4340 (*i)->reset_visual_state ();
4344 _routes->update_visibility ();
4347 /** This is the core function that controls the zoom level of the canvas. It is called
4348 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4349 * @param spp new number of samples per pixel
4352 Editor::set_samples_per_pixel (framecnt_t spp)
4358 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4359 const framecnt_t lots_of_pixels = 4000;
4361 /* if the zoom level is greater than what you'd get trying to display 3
4362 * days of audio on a really big screen, then it's too big.
4365 if (spp * lots_of_pixels > three_days) {
4369 samples_per_pixel = spp;
4372 tempo_lines->tempo_map_changed();
4375 bool const showing_time_selection = selection->time.length() > 0;
4377 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4378 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4379 (*i)->reshow_selection (selection->time);
4383 ZoomChanged (); /* EMIT_SIGNAL */
4385 ArdourCanvas::GtkCanvasViewport* c;
4387 c = get_track_canvas();
4389 c->canvas()->zoomed ();
4392 if (playhead_cursor) {
4393 playhead_cursor->set_position (playhead_cursor->current_frame ());
4396 refresh_location_display();
4397 _summary->set_overlays_dirty ();
4399 update_marker_labels ();
4405 Editor::queue_visual_videotimeline_update ()
4408 * pending_visual_change.add (VisualChange::VideoTimeline);
4409 * or maybe even more specific: which videotimeline-image
4410 * currently it calls update_video_timeline() to update
4411 * _all outdated_ images on the video-timeline.
4412 * see 'exposeimg()' in video_image_frame.cc
4414 ensure_visual_change_idle_handler ();
4418 Editor::ensure_visual_change_idle_handler ()
4420 if (pending_visual_change.idle_handler_id < 0) {
4421 // see comment in add_to_idle_resize above.
4422 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4423 pending_visual_change.being_handled = false;
4428 Editor::_idle_visual_changer (void* arg)
4430 return static_cast<Editor*>(arg)->idle_visual_changer ();
4434 Editor::idle_visual_changer ()
4436 /* set_horizontal_position() below (and maybe other calls) call
4437 gtk_main_iteration(), so it's possible that a signal will be handled
4438 half-way through this method. If this signal wants an
4439 idle_visual_changer we must schedule another one after this one, so
4440 mark the idle_handler_id as -1 here to allow that. Also make a note
4441 that we are doing the visual change, so that changes in response to
4442 super-rapid-screen-update can be dropped if we are still processing
4446 pending_visual_change.idle_handler_id = -1;
4447 pending_visual_change.being_handled = true;
4449 VisualChange vc = pending_visual_change;
4451 pending_visual_change.pending = (VisualChange::Type) 0;
4453 visual_changer (vc);
4455 pending_visual_change.being_handled = false;
4457 return 0; /* this is always a one-shot call */
4461 Editor::visual_changer (const VisualChange& vc)
4463 double const last_time_origin = horizontal_position ();
4465 if (vc.pending & VisualChange::ZoomLevel) {
4466 set_samples_per_pixel (vc.samples_per_pixel);
4468 compute_fixed_ruler_scale ();
4470 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4471 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4473 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4474 current_bbt_points_begin, current_bbt_points_end);
4475 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4476 current_bbt_points_begin, current_bbt_points_end);
4477 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4479 update_video_timeline();
4482 if (vc.pending & VisualChange::TimeOrigin) {
4483 set_horizontal_position (vc.time_origin / samples_per_pixel);
4486 if (vc.pending & VisualChange::YOrigin) {
4487 vertical_adjustment.set_value (vc.y_origin);
4490 if (last_time_origin == horizontal_position ()) {
4491 /* changed signal not emitted */
4492 update_fixed_rulers ();
4493 redisplay_tempo (true);
4496 if (!(vc.pending & VisualChange::ZoomLevel)) {
4497 update_video_timeline();
4500 _summary->set_overlays_dirty ();
4503 struct EditorOrderTimeAxisSorter {
4504 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4505 return a->order () < b->order ();
4510 Editor::sort_track_selection (TrackViewList& sel)
4512 EditorOrderTimeAxisSorter cmp;
4517 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4520 framepos_t where = 0;
4521 EditPoint ep = _edit_point;
4523 if (Profile->get_mixbus())
4524 if (ep == EditAtSelectedMarker)
4525 ep = EditAtPlayhead;
4527 if (from_outside_canvas && (ep == EditAtMouse)) {
4528 ep = EditAtPlayhead;
4529 } else if (from_context_menu && (ep == EditAtMouse)) {
4530 return canvas_event_sample (&context_click_event, 0, 0);
4533 if (entered_marker) {
4534 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4535 return entered_marker->position();
4538 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4539 ep = EditAtSelectedMarker;
4542 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4543 ep = EditAtPlayhead;
4547 case EditAtPlayhead:
4548 if (_dragging_playhead) {
4549 where = *_control_scroll_target;
4551 where = _session->audible_frame();
4553 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4556 case EditAtSelectedMarker:
4557 if (!selection->markers.empty()) {
4559 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4562 where = loc->start();
4566 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4574 if (!mouse_frame (where, ignored)) {
4575 /* XXX not right but what can we do ? */
4579 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4587 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4589 if (!_session) return;
4591 begin_reversible_command (cmd);
4595 if ((tll = transport_loop_location()) == 0) {
4596 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4597 XMLNode &before = _session->locations()->get_state();
4598 _session->locations()->add (loc, true);
4599 _session->set_auto_loop_location (loc);
4600 XMLNode &after = _session->locations()->get_state();
4601 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4603 XMLNode &before = tll->get_state();
4604 tll->set_hidden (false, this);
4605 tll->set (start, end);
4606 XMLNode &after = tll->get_state();
4607 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4610 commit_reversible_command ();
4614 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4616 if (!_session) return;
4618 begin_reversible_command (cmd);
4622 if ((tpl = transport_punch_location()) == 0) {
4623 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4624 XMLNode &before = _session->locations()->get_state();
4625 _session->locations()->add (loc, true);
4626 _session->set_auto_punch_location (loc);
4627 XMLNode &after = _session->locations()->get_state();
4628 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4630 XMLNode &before = tpl->get_state();
4631 tpl->set_hidden (false, this);
4632 tpl->set (start, end);
4633 XMLNode &after = tpl->get_state();
4634 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4637 commit_reversible_command ();
4640 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4641 * @param rs List to which found regions are added.
4642 * @param where Time to look at.
4643 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4646 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4648 const TrackViewList* tracks;
4651 tracks = &track_views;
4656 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4658 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4661 boost::shared_ptr<Track> tr;
4662 boost::shared_ptr<Playlist> pl;
4664 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4666 boost::shared_ptr<RegionList> regions = pl->regions_at (
4667 (framepos_t) floor ( (double) where * tr->speed()));
4669 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4670 RegionView* rv = rtv->view()->find_view (*i);
4681 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4683 const TrackViewList* tracks;
4686 tracks = &track_views;
4691 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4692 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4694 boost::shared_ptr<Track> tr;
4695 boost::shared_ptr<Playlist> pl;
4697 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4699 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4700 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4702 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4704 RegionView* rv = rtv->view()->find_view (*i);
4715 /** Get regions using the following method:
4717 * Make a region list using:
4718 * (a) any selected regions
4719 * (b) the intersection of any selected tracks and the edit point(*)
4720 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4722 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4724 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4728 Editor::get_regions_from_selection_and_edit_point ()
4730 RegionSelection regions;
4732 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4733 regions.add (entered_regionview);
4735 regions = selection->regions;
4738 if ( regions.empty() ) {
4739 TrackViewList tracks = selection->tracks;
4741 if (!tracks.empty()) {
4742 /* no region selected or entered, but some selected tracks:
4743 * act on all regions on the selected tracks at the edit point
4745 framepos_t const where = get_preferred_edit_position ();
4746 get_regions_at(regions, where, tracks);
4753 /** Get regions using the following method:
4755 * Make a region list using:
4756 * (a) any selected regions
4757 * (b) the intersection of any selected tracks and the edit point(*)
4758 * (c) if neither exists, then whatever region is under the mouse
4760 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4762 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4765 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4767 RegionSelection regions;
4769 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4770 regions.add (entered_regionview);
4772 regions = selection->regions;
4775 if ( regions.empty() ) {
4776 TrackViewList tracks = selection->tracks;
4778 if (!tracks.empty()) {
4779 /* no region selected or entered, but some selected tracks:
4780 * act on all regions on the selected tracks at the edit point
4782 get_regions_at(regions, pos, tracks);
4789 /** Start with regions that are selected, or the entered regionview if none are selected.
4790 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4791 * of the regions that we started with.
4795 Editor::get_regions_from_selection_and_entered ()
4797 RegionSelection regions = selection->regions;
4799 if (regions.empty() && entered_regionview) {
4800 regions.add (entered_regionview);
4807 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4809 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4810 RouteTimeAxisView* rtav;
4812 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4813 boost::shared_ptr<Playlist> pl;
4814 std::vector<boost::shared_ptr<Region> > results;
4815 boost::shared_ptr<Track> tr;
4817 if ((tr = rtav->track()) == 0) {
4822 if ((pl = (tr->playlist())) != 0) {
4823 boost::shared_ptr<Region> r = pl->region_by_id (id);
4825 RegionView* rv = rtav->view()->find_view (r);
4827 regions.push_back (rv);
4836 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4839 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4840 MidiTimeAxisView* mtav;
4842 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4844 mtav->get_per_region_note_selection (selection);
4851 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4853 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4855 RouteTimeAxisView* tatv;
4857 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4859 boost::shared_ptr<Playlist> pl;
4860 vector<boost::shared_ptr<Region> > results;
4862 boost::shared_ptr<Track> tr;
4864 if ((tr = tatv->track()) == 0) {
4869 if ((pl = (tr->playlist())) != 0) {
4870 if (src_comparison) {
4871 pl->get_source_equivalent_regions (region, results);
4873 pl->get_region_list_equivalent_regions (region, results);
4877 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4878 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4879 regions.push_back (marv);
4888 Editor::show_rhythm_ferret ()
4890 if (rhythm_ferret == 0) {
4891 rhythm_ferret = new RhythmFerret(*this);
4894 rhythm_ferret->set_session (_session);
4895 rhythm_ferret->show ();
4896 rhythm_ferret->present ();
4900 Editor::first_idle ()
4902 MessageDialog* dialog = 0;
4904 if (track_views.size() > 1) {
4905 Timers::TimerSuspender t;
4906 dialog = new MessageDialog (
4907 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4911 ARDOUR_UI::instance()->flush_pending ();
4914 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4918 // first idle adds route children (automation tracks), so we need to redisplay here
4919 _routes->redisplay ();
4923 if (_session->undo_depth() == 0) {
4924 undo_action->set_sensitive(false);
4926 redo_action->set_sensitive(false);
4927 begin_selection_op_history ();
4933 Editor::_idle_resize (gpointer arg)
4935 return ((Editor*)arg)->idle_resize ();
4939 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4941 if (resize_idle_id < 0) {
4942 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
4943 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
4944 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
4946 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
4947 _pending_resize_amount = 0;
4950 /* make a note of the smallest resulting height, so that we can clamp the
4951 lower limit at TimeAxisView::hSmall */
4953 int32_t min_resulting = INT32_MAX;
4955 _pending_resize_amount += h;
4956 _pending_resize_view = view;
4958 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4960 if (selection->tracks.contains (_pending_resize_view)) {
4961 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4962 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4966 if (min_resulting < 0) {
4971 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4972 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4976 /** Handle pending resizing of tracks */
4978 Editor::idle_resize ()
4980 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4982 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4983 selection->tracks.contains (_pending_resize_view)) {
4985 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4986 if (*i != _pending_resize_view) {
4987 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4992 _pending_resize_amount = 0;
4993 _group_tabs->set_dirty ();
4994 resize_idle_id = -1;
5002 ENSURE_GUI_THREAD (*this, &Editor::located);
5005 playhead_cursor->set_position (_session->audible_frame ());
5006 if (_follow_playhead && !_pending_initial_locate) {
5007 reset_x_origin_to_follow_playhead ();
5011 _pending_locate_request = false;
5012 _pending_initial_locate = false;
5016 Editor::region_view_added (RegionView * rv)
5018 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5019 if (rv->region ()->id () == (*pr)) {
5020 selection->add (rv);
5021 selection->regions.pending.erase (pr);
5026 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5028 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5029 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5030 if (rv->region()->id () == (*rnote).first) {
5031 mrv->select_notes ((*rnote).second);
5032 selection->pending_midi_note_selection.erase(rnote);
5038 _summary->set_background_dirty ();
5042 Editor::region_view_removed ()
5044 _summary->set_background_dirty ();
5048 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5050 TrackViewList::const_iterator j = track_views.begin ();
5051 while (j != track_views.end()) {
5052 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5053 if (rtv && rtv->route() == r) {
5064 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5068 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5069 TimeAxisView* tv = axis_view_from_route (*i);
5079 Editor::suspend_route_redisplay ()
5082 _routes->suspend_redisplay();
5087 Editor::resume_route_redisplay ()
5090 _routes->redisplay(); // queue redisplay
5091 _routes->resume_redisplay();
5096 Editor::add_routes (RouteList& routes)
5098 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5100 RouteTimeAxisView *rtv;
5101 list<RouteTimeAxisView*> new_views;
5102 TrackViewList new_selection;
5103 bool from_scratch = (track_views.size() == 0);
5105 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5106 boost::shared_ptr<Route> route = (*x);
5108 if (route->is_auditioner() || route->is_monitor()) {
5112 DataType dt = route->input()->default_type();
5114 if (dt == ARDOUR::DataType::AUDIO) {
5115 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5116 rtv->set_route (route);
5117 } else if (dt == ARDOUR::DataType::MIDI) {
5118 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5119 rtv->set_route (route);
5121 throw unknown_type();
5124 new_views.push_back (rtv);
5125 track_views.push_back (rtv);
5126 new_selection.push_back (rtv);
5128 rtv->effective_gain_display ();
5130 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5131 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5134 if (new_views.size() > 0) {
5135 _routes->routes_added (new_views);
5136 _summary->routes_added (new_views);
5139 if (!from_scratch) {
5140 selection->tracks.clear();
5141 selection->add (new_selection);
5142 begin_selection_op_history();
5145 if (show_editor_mixer_when_tracks_arrive) {
5146 show_editor_mixer (true);
5149 editor_list_button.set_sensitive (true);
5153 Editor::timeaxisview_deleted (TimeAxisView *tv)
5155 if (tv == entered_track) {
5159 if (_session && _session->deletion_in_progress()) {
5160 /* the situation is under control */
5164 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5166 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5168 _routes->route_removed (tv);
5170 TimeAxisView::Children c = tv->get_child_list ();
5171 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5172 if (entered_track == i->get()) {
5177 /* remove it from the list of track views */
5179 TrackViewList::iterator i;
5181 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5182 i = track_views.erase (i);
5185 /* update whatever the current mixer strip is displaying, if revelant */
5187 boost::shared_ptr<Route> route;
5190 route = rtav->route ();
5193 if (current_mixer_strip && current_mixer_strip->route() == route) {
5195 TimeAxisView* next_tv;
5197 if (track_views.empty()) {
5199 } else if (i == track_views.end()) {
5200 next_tv = track_views.front();
5207 set_selected_mixer_strip (*next_tv);
5209 /* make the editor mixer strip go away setting the
5210 * button to inactive (which also unticks the menu option)
5213 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5219 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5221 if (apply_to_selection) {
5222 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5224 TrackSelection::iterator j = i;
5227 hide_track_in_display (*i, false);
5232 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5234 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5235 // this will hide the mixer strip
5236 set_selected_mixer_strip (*tv);
5239 _routes->hide_track_in_display (*tv);
5244 Editor::sync_track_view_list_and_routes ()
5246 track_views = TrackViewList (_routes->views ());
5248 _summary->set_background_dirty();
5249 _group_tabs->set_dirty ();
5251 return false; // do not call again (until needed)
5255 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5257 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5262 /** Find a RouteTimeAxisView by the ID of its route */
5264 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5266 RouteTimeAxisView* v;
5268 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5269 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5270 if(v->route()->id() == id) {
5280 Editor::fit_route_group (RouteGroup *g)
5282 TrackViewList ts = axis_views_from_routes (g->route_list ());
5287 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5289 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5292 _session->cancel_audition ();
5296 if (_session->is_auditioning()) {
5297 _session->cancel_audition ();
5298 if (r == last_audition_region) {
5303 _session->audition_region (r);
5304 last_audition_region = r;
5309 Editor::hide_a_region (boost::shared_ptr<Region> r)
5311 r->set_hidden (true);
5315 Editor::show_a_region (boost::shared_ptr<Region> r)
5317 r->set_hidden (false);
5321 Editor::audition_region_from_region_list ()
5323 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5327 Editor::hide_region_from_region_list ()
5329 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5333 Editor::show_region_in_region_list ()
5335 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5339 Editor::step_edit_status_change (bool yn)
5342 start_step_editing ();
5344 stop_step_editing ();
5349 Editor::start_step_editing ()
5351 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5355 Editor::stop_step_editing ()
5357 step_edit_connection.disconnect ();
5361 Editor::check_step_edit ()
5363 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5364 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5366 mtv->check_step_edit ();
5370 return true; // do it again, till we stop
5374 Editor::scroll_press (Direction dir)
5376 ++_scroll_callbacks;
5378 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5379 /* delay the first auto-repeat */
5385 scroll_backward (1);
5393 scroll_up_one_track ();
5397 scroll_down_one_track ();
5401 /* do hacky auto-repeat */
5402 if (!_scroll_connection.connected ()) {
5404 _scroll_connection = Glib::signal_timeout().connect (
5405 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5408 _scroll_callbacks = 0;
5415 Editor::scroll_release ()
5417 _scroll_connection.disconnect ();
5420 /** Queue a change for the Editor viewport x origin to follow the playhead */
5422 Editor::reset_x_origin_to_follow_playhead ()
5424 framepos_t const frame = playhead_cursor->current_frame ();
5426 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5428 if (_session->transport_speed() < 0) {
5430 if (frame > (current_page_samples() / 2)) {
5431 center_screen (frame-(current_page_samples()/2));
5433 center_screen (current_page_samples()/2);
5440 if (frame < leftmost_frame) {
5442 if (_session->transport_rolling()) {
5443 /* rolling; end up with the playhead at the right of the page */
5444 l = frame - current_page_samples ();
5446 /* not rolling: end up with the playhead 1/4 of the way along the page */
5447 l = frame - current_page_samples() / 4;
5451 if (_session->transport_rolling()) {
5452 /* rolling: end up with the playhead on the left of the page */
5455 /* not rolling: end up with the playhead 3/4 of the way along the page */
5456 l = frame - 3 * current_page_samples() / 4;
5464 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5470 Editor::super_rapid_screen_update ()
5472 if (!_session || !_session->engine().running()) {
5476 /* METERING / MIXER STRIPS */
5478 /* update track meters, if required */
5479 if (contents().is_mapped() && meters_running) {
5480 RouteTimeAxisView* rtv;
5481 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5482 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5483 rtv->fast_update ();
5488 /* and any current mixer strip */
5489 if (current_mixer_strip) {
5490 current_mixer_strip->fast_update ();
5493 /* PLAYHEAD AND VIEWPORT */
5495 framepos_t const frame = _session->audible_frame();
5497 /* There are a few reasons why we might not update the playhead / viewport stuff:
5499 * 1. we don't update things when there's a pending locate request, otherwise
5500 * when the editor requests a locate there is a chance that this method
5501 * will move the playhead before the locate request is processed, causing
5503 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5504 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5507 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5509 last_update_frame = frame;
5511 if (!_dragging_playhead) {
5512 playhead_cursor->set_position (frame);
5515 if (!_stationary_playhead) {
5517 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5518 /* We only do this if we aren't already
5519 handling a visual change (ie if
5520 pending_visual_change.being_handled is
5521 false) so that these requests don't stack
5522 up there are too many of them to handle in
5525 reset_x_origin_to_follow_playhead ();
5530 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5531 framepos_t const frame = playhead_cursor->current_frame ();
5532 double target = ((double)frame - (double)current_page_samples()/2.0);
5533 if (target <= 0.0) {
5536 // compare to EditorCursor::set_position()
5537 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5538 double const new_pos = sample_to_pixel_unrounded (target);
5539 if (rint (new_pos) != rint (old_pos)) {
5540 reset_x_origin (pixel_to_sample (floor (new_pos)));
5551 Editor::session_going_away ()
5553 _have_idled = false;
5555 _session_connections.drop_connections ();
5557 super_rapid_screen_update_connection.disconnect ();
5559 selection->clear ();
5560 cut_buffer->clear ();
5562 clicked_regionview = 0;
5563 clicked_axisview = 0;
5564 clicked_routeview = 0;
5565 entered_regionview = 0;
5567 last_update_frame = 0;
5570 playhead_cursor->hide ();
5572 /* rip everything out of the list displays */
5576 _route_groups->clear ();
5578 /* do this first so that deleting a track doesn't reset cms to null
5579 and thus cause a leak.
5582 if (current_mixer_strip) {
5583 if (current_mixer_strip->get_parent() != 0) {
5584 global_hpacker.remove (*current_mixer_strip);
5586 delete current_mixer_strip;
5587 current_mixer_strip = 0;
5590 /* delete all trackviews */
5592 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5595 track_views.clear ();
5597 nudge_clock->set_session (0);
5599 editor_list_button.set_active(false);
5600 editor_list_button.set_sensitive(false);
5602 /* clear tempo/meter rulers */
5603 remove_metric_marks ();
5605 clear_marker_display ();
5607 stop_step_editing ();
5611 /* get rid of any existing editor mixer strip */
5613 WindowTitle title(Glib::get_application_name());
5614 title += _("Editor");
5616 own_window()->set_title (title.get_string());
5619 SessionHandlePtr::session_going_away ();
5624 Editor::show_editor_list (bool yn)
5627 _the_notebook.show ();
5629 _the_notebook.hide ();
5634 Editor::change_region_layering_order (bool from_context_menu)
5636 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5638 if (!clicked_routeview) {
5639 if (layering_order_editor) {
5640 layering_order_editor->hide ();
5645 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5651 boost::shared_ptr<Playlist> pl = track->playlist();
5657 if (layering_order_editor == 0) {
5658 layering_order_editor = new RegionLayeringOrderEditor (*this);
5661 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5662 layering_order_editor->maybe_present ();
5666 Editor::update_region_layering_order_editor ()
5668 if (layering_order_editor && layering_order_editor->is_visible ()) {
5669 change_region_layering_order (true);
5674 Editor::setup_fade_images ()
5676 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5677 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5678 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5679 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5680 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5682 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5683 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5684 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5685 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5686 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5688 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5689 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5690 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5691 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5692 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5694 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5695 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5696 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5697 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5698 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5702 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5704 Editor::action_menu_item (std::string const & name)
5706 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5709 return *manage (a->create_menu_item ());
5713 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5715 EventBox* b = manage (new EventBox);
5716 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5717 Label* l = manage (new Label (name));
5721 _the_notebook.append_page (widget, *b);
5725 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5727 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5728 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5731 if (ev->type == GDK_2BUTTON_PRESS) {
5733 /* double-click on a notebook tab shrinks or expands the notebook */
5735 if (_notebook_shrunk) {
5736 if (pre_notebook_shrink_pane_width) {
5737 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5739 _notebook_shrunk = false;
5741 pre_notebook_shrink_pane_width = edit_pane.get_position();
5743 /* this expands the LHS of the edit pane to cover the notebook
5744 PAGE but leaves the tabs visible.
5746 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5747 _notebook_shrunk = true;
5755 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5757 using namespace Menu_Helpers;
5759 MenuList& items = _control_point_context_menu.items ();
5762 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5763 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5764 if (!can_remove_control_point (item)) {
5765 items.back().set_sensitive (false);
5768 _control_point_context_menu.popup (event->button.button, event->button.time);
5772 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5774 using namespace Menu_Helpers;
5776 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5781 /* We need to get the selection here and pass it to the operations, since
5782 popping up the menu will cause a region leave event which clears
5783 entered_regionview. */
5785 MidiRegionView& mrv = note->region_view();
5786 const RegionSelection rs = get_regions_from_selection_and_entered ();
5787 const uint32_t sel_size = mrv.selection_size ();
5789 MenuList& items = _note_context_menu.items();
5793 items.push_back(MenuElem(_("Delete"),
5794 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5797 items.push_back(MenuElem(_("Edit..."),
5798 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5799 if (sel_size != 1) {
5800 items.back().set_sensitive (false);
5803 items.push_back(MenuElem(_("Transpose..."),
5804 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
5807 items.push_back(MenuElem(_("Legatize"),
5808 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5810 items.back().set_sensitive (false);
5813 items.push_back(MenuElem(_("Quantize..."),
5814 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5816 items.push_back(MenuElem(_("Remove Overlap"),
5817 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5819 items.back().set_sensitive (false);
5822 items.push_back(MenuElem(_("Transform..."),
5823 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5825 _note_context_menu.popup (event->button.button, event->button.time);
5829 Editor::zoom_vertical_modifier_released()
5831 _stepping_axis_view = 0;
5835 Editor::ui_parameter_changed (string parameter)
5837 if (parameter == "icon-set") {
5838 while (!_cursor_stack.empty()) {
5839 _cursor_stack.pop_back();
5841 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
5842 _cursor_stack.push_back(_cursors->grabber);
5843 } else if (parameter == "draggable-playhead") {
5844 if (_verbose_cursor) {
5845 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
5851 Editor::use_own_window (bool and_fill_it)
5853 bool new_window = !own_window();
5855 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
5857 if (win && new_window) {
5858 win->set_name ("EditorWindow");
5860 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
5862 // win->signal_realize().connect (*this, &Editor::on_realize);
5863 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
5864 win->set_data ("ardour-bindings", bindings);
5869 DisplaySuspender ds;
5870 contents().show_all ();
5872 /* XXX: this is a bit unfortunate; it would probably
5873 be nicer if we could just call show () above rather
5874 than needing the show_all ()
5877 /* re-hide stuff if necessary */
5878 editor_list_button_toggled ();
5879 parameter_changed ("show-summary");
5880 parameter_changed ("show-group-tabs");
5881 parameter_changed ("show-zoom-tools");
5883 /* now reset all audio_time_axis heights, because widgets might need
5889 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5890 tv = (static_cast<TimeAxisView*>(*i));
5891 tv->reset_height ();
5894 if (current_mixer_strip) {
5895 current_mixer_strip->hide_things ();
5896 current_mixer_strip->parameter_changed ("mixer-element-visibility");