2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include <gtkmm2ext/keyboard.h>
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
68 #include "ardour/audio_track.h"
69 #include "ardour/audioengine.h"
70 #include "ardour/audioregion.h"
71 #include "ardour/lmath.h"
72 #include "ardour/location.h"
73 #include "ardour/profile.h"
74 #include "ardour/route_group.h"
75 #include "ardour/session_playlists.h"
76 #include "ardour/tempo.h"
77 #include "ardour/utils.h"
79 #include "canvas/debug.h"
80 #include "canvas/text.h"
82 #include "control_protocol/control_protocol.h"
85 #include "analysis_window.h"
86 #include "audio_clock.h"
87 #include "audio_region_view.h"
88 #include "audio_streamview.h"
89 #include "audio_time_axis.h"
90 #include "automation_time_axis.h"
91 #include "bundle_manager.h"
92 #include "crossfade_edit.h"
96 #include "editor_cursors.h"
97 #include "editor_drag.h"
98 #include "editor_group_tabs.h"
99 #include "editor_locations.h"
100 #include "editor_regions.h"
101 #include "editor_route_groups.h"
102 #include "editor_routes.h"
103 #include "editor_snapshots.h"
104 #include "editor_summary.h"
105 #include "global_port_matrix.h"
106 #include "gui_object.h"
107 #include "gui_thread.h"
108 #include "keyboard.h"
109 #include "luainstance.h"
111 #include "midi_region_view.h"
112 #include "midi_time_axis.h"
113 #include "mixer_strip.h"
114 #include "mixer_ui.h"
115 #include "mouse_cursors.h"
116 #include "note_base.h"
117 #include "playlist_selector.h"
118 #include "public_editor.h"
119 #include "quantize_dialog.h"
120 #include "region_layering_order_editor.h"
121 #include "rgb_macros.h"
122 #include "rhythm_ferret.h"
123 #include "selection.h"
125 #include "tempo_lines.h"
126 #include "time_axis_view.h"
128 #include "tooltips.h"
129 #include "ui_config.h"
131 #include "verbose_cursor.h"
136 using namespace ARDOUR;
137 using namespace ARDOUR_UI_UTILS;
140 using namespace Glib;
141 using namespace Gtkmm2ext;
142 using namespace Editing;
144 using PBD::internationalize;
146 using Gtkmm2ext::Keyboard;
148 double Editor::timebar_height = 15.0;
150 static const gchar *_snap_type_strings[] = {
184 static const gchar *_snap_mode_strings[] = {
191 static const gchar *_edit_point_strings[] = {
198 static const gchar *_edit_mode_strings[] = {
206 static const gchar *_zoom_focus_strings[] = {
216 #ifdef USE_RUBBERBAND
217 static const gchar *_rb_opt_strings[] = {
220 N_("Balanced multitimbral mixture"),
221 N_("Unpitched percussion with stable notes"),
222 N_("Crisp monophonic instrumental"),
223 N_("Unpitched solo percussion"),
224 N_("Resample without preserving pitch"),
229 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
232 pane_size_watcher (Paned* pane)
234 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
238 Quartz: impossible to access
240 so stop that by preventing it from ever getting too narrow. 35
241 pixels is basically a rough guess at the tab width.
246 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
248 gint pos = pane->get_position ();
250 if (pos > max_width_of_lhs) {
251 pane->set_position (max_width_of_lhs);
256 : PublicEditor (global_hpacker)
257 , editor_mixer_strip_width (Wide)
258 , constructed (false)
259 , _playlist_selector (0)
260 , no_save_visual (false)
262 , samples_per_pixel (2048)
263 , zoom_focus (ZoomFocusPlayhead)
264 , mouse_mode (MouseObject)
265 , pre_internal_snap_type (SnapToBeat)
266 , pre_internal_snap_mode (SnapOff)
267 , internal_snap_type (SnapToBeat)
268 , internal_snap_mode (SnapOff)
269 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
270 , _notebook_shrunk (false)
271 , location_marker_color (0)
272 , location_range_color (0)
273 , location_loop_color (0)
274 , location_punch_color (0)
275 , location_cd_marker_color (0)
277 , _show_marker_lines (false)
278 , clicked_axisview (0)
279 , clicked_routeview (0)
280 , clicked_regionview (0)
281 , clicked_selection (0)
282 , clicked_control_point (0)
283 , button_release_can_deselect (true)
284 , _mouse_changed_selection (false)
285 , region_edit_menu_split_item (0)
286 , region_edit_menu_split_multichannel_item (0)
287 , track_region_edit_playlist_menu (0)
288 , track_edit_playlist_submenu (0)
289 , track_selection_edit_playlist_submenu (0)
290 , _popup_region_menu_item (0)
292 , _track_canvas_viewport (0)
293 , within_track_canvas (false)
294 , _verbose_cursor (0)
298 , range_marker_group (0)
299 , transport_marker_group (0)
300 , cd_marker_group (0)
301 , _time_markers_group (0)
302 , hv_scroll_group (0)
304 , cursor_scroll_group (0)
305 , no_scroll_group (0)
306 , _trackview_group (0)
307 , _drag_motion_group (0)
308 , _canvas_drop_zone (0)
309 , no_ruler_shown_update (false)
310 , ruler_grabbed_widget (0)
312 , minsec_mark_interval (0)
313 , minsec_mark_modulo (0)
315 , timecode_mark_modulo (0)
316 , timecode_nmarks (0)
317 , _samples_ruler_interval (0)
320 , bbt_bar_helper_on (0)
321 , bbt_accent_modulo (0)
326 , visible_timebars (0)
327 , editor_ruler_menu (0)
331 , range_marker_bar (0)
332 , transport_marker_bar (0)
334 , minsec_label (_("Mins:Secs"))
335 , bbt_label (_("Bars:Beats"))
336 , timecode_label (_("Timecode"))
337 , samples_label (_("Samples"))
338 , tempo_label (_("Tempo"))
339 , meter_label (_("Meter"))
340 , mark_label (_("Location Markers"))
341 , range_mark_label (_("Range Markers"))
342 , transport_mark_label (_("Loop/Punch Ranges"))
343 , cd_mark_label (_("CD Markers"))
344 , videotl_label (_("Video Timeline"))
346 , playhead_cursor (0)
347 , edit_packer (4, 4, true)
348 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
349 , horizontal_adjustment (0.0, 0.0, 1e16)
350 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
351 , controls_layout (unused_adjustment, vertical_adjustment)
352 , _scroll_callbacks (0)
353 , _visible_canvas_width (0)
354 , _visible_canvas_height (0)
355 , _full_canvas_height (0)
356 , edit_controls_left_menu (0)
357 , edit_controls_right_menu (0)
358 , last_update_frame (0)
359 , cut_buffer_start (0)
360 , cut_buffer_length (0)
361 , button_bindings (0)
365 , current_interthread_info (0)
366 , analysis_window (0)
367 , select_new_marker (false)
369 , scrubbing_direction (0)
370 , scrub_reversals (0)
371 , scrub_reverse_distance (0)
372 , have_pending_keyboard_selection (false)
373 , pending_keyboard_selection_start (0)
374 , _snap_type (SnapToBeat)
375 , _snap_mode (SnapOff)
376 , snap_threshold (5.0)
377 , ignore_gui_changes (false)
378 , _drags (new DragManager (this))
380 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
381 , _dragging_playhead (false)
382 , _dragging_edit_point (false)
383 , _show_measures (true)
384 , _follow_playhead (true)
385 , _stationary_playhead (false)
388 , global_rect_group (0)
389 , time_line_group (0)
390 , tempo_or_meter_marker_menu (0)
392 , range_marker_menu (0)
393 , transport_marker_menu (0)
394 , new_transport_marker_menu (0)
396 , marker_menu_item (0)
397 , bbt_beat_subdivision (4)
398 , _visible_track_count (-1)
399 , toolbar_selection_clock_table (2,3)
400 , automation_mode_button (_("mode"))
401 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
402 , selection (new Selection (this))
403 , cut_buffer (new Selection (this))
404 , _selection_memento (new SelectionMemento())
405 , _all_region_actions_sensitized (false)
406 , _ignore_region_action (false)
407 , _last_region_menu_was_main (false)
408 , _ignore_follow_edits (false)
409 , cd_marker_bar_drag_rect (0)
410 , range_bar_drag_rect (0)
411 , transport_bar_drag_rect (0)
412 , transport_bar_range_rect (0)
413 , transport_bar_preroll_rect (0)
414 , transport_bar_postroll_rect (0)
415 , transport_loop_range_rect (0)
416 , transport_punch_range_rect (0)
417 , transport_punchin_line (0)
418 , transport_punchout_line (0)
419 , transport_preroll_rect (0)
420 , transport_postroll_rect (0)
422 , rubberband_rect (0)
428 , autoscroll_horizontal_allowed (false)
429 , autoscroll_vertical_allowed (false)
431 , autoscroll_widget (0)
432 , show_gain_after_trim (false)
433 , selection_op_cmd_depth (0)
434 , selection_op_history_it (0)
436 , current_mixer_strip (0)
437 , show_editor_mixer_when_tracks_arrive (false)
438 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
439 , current_stepping_trackview (0)
440 , last_track_height_step_timestamp (0)
442 , entered_regionview (0)
443 , clear_entered_track (false)
444 , _edit_point (EditAtMouse)
445 , meters_running (false)
447 , _have_idled (false)
448 , resize_idle_id (-1)
449 , _pending_resize_amount (0)
450 , _pending_resize_view (0)
451 , _pending_locate_request (false)
452 , _pending_initial_locate (false)
456 , layering_order_editor (0)
457 , _last_cut_copy_source_track (0)
458 , _region_selection_change_updates_region_list (true)
460 , _following_mixer_selection (false)
461 , _control_point_toggled_on_press (false)
462 , _stepping_axis_view (0)
463 , quantize_dialog (0)
464 , _main_menu_disabler (0)
465 , myactions (X_("editor"))
467 /* we are a singleton */
469 PublicEditor::_instance = this;
473 last_event_time.tv_sec = 0;
474 last_event_time.tv_usec = 0;
476 selection_op_history.clear();
479 snap_type_strings = I18N (_snap_type_strings);
480 snap_mode_strings = I18N (_snap_mode_strings);
481 zoom_focus_strings = I18N (_zoom_focus_strings);
482 edit_mode_strings = I18N (_edit_mode_strings);
483 edit_point_strings = I18N (_edit_point_strings);
484 #ifdef USE_RUBBERBAND
485 rb_opt_strings = I18N (_rb_opt_strings);
489 build_edit_mode_menu();
490 build_zoom_focus_menu();
491 build_track_count_menu();
492 build_snap_mode_menu();
493 build_snap_type_menu();
494 build_edit_point_menu();
496 location_marker_color = UIConfiguration::instance().color ("location marker");
497 location_range_color = UIConfiguration::instance().color ("location range");
498 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
499 location_loop_color = UIConfiguration::instance().color ("location loop");
500 location_punch_color = UIConfiguration::instance().color ("location punch");
502 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
504 TimeAxisView::setup_sizes ();
505 ArdourMarker::setup_sizes (timebar_height);
507 bbt_label.set_name ("EditorRulerLabel");
508 bbt_label.set_size_request (-1, (int)timebar_height);
509 bbt_label.set_alignment (1.0, 0.5);
510 bbt_label.set_padding (5,0);
512 bbt_label.set_no_show_all();
513 minsec_label.set_name ("EditorRulerLabel");
514 minsec_label.set_size_request (-1, (int)timebar_height);
515 minsec_label.set_alignment (1.0, 0.5);
516 minsec_label.set_padding (5,0);
517 minsec_label.hide ();
518 minsec_label.set_no_show_all();
519 timecode_label.set_name ("EditorRulerLabel");
520 timecode_label.set_size_request (-1, (int)timebar_height);
521 timecode_label.set_alignment (1.0, 0.5);
522 timecode_label.set_padding (5,0);
523 timecode_label.hide ();
524 timecode_label.set_no_show_all();
525 samples_label.set_name ("EditorRulerLabel");
526 samples_label.set_size_request (-1, (int)timebar_height);
527 samples_label.set_alignment (1.0, 0.5);
528 samples_label.set_padding (5,0);
529 samples_label.hide ();
530 samples_label.set_no_show_all();
532 tempo_label.set_name ("EditorRulerLabel");
533 tempo_label.set_size_request (-1, (int)timebar_height);
534 tempo_label.set_alignment (1.0, 0.5);
535 tempo_label.set_padding (5,0);
537 tempo_label.set_no_show_all();
539 meter_label.set_name ("EditorRulerLabel");
540 meter_label.set_size_request (-1, (int)timebar_height);
541 meter_label.set_alignment (1.0, 0.5);
542 meter_label.set_padding (5,0);
544 meter_label.set_no_show_all();
546 if (Profile->get_trx()) {
547 mark_label.set_text (_("Markers"));
549 mark_label.set_name ("EditorRulerLabel");
550 mark_label.set_size_request (-1, (int)timebar_height);
551 mark_label.set_alignment (1.0, 0.5);
552 mark_label.set_padding (5,0);
554 mark_label.set_no_show_all();
556 cd_mark_label.set_name ("EditorRulerLabel");
557 cd_mark_label.set_size_request (-1, (int)timebar_height);
558 cd_mark_label.set_alignment (1.0, 0.5);
559 cd_mark_label.set_padding (5,0);
560 cd_mark_label.hide();
561 cd_mark_label.set_no_show_all();
563 videotl_bar_height = 4;
564 videotl_label.set_name ("EditorRulerLabel");
565 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
566 videotl_label.set_alignment (1.0, 0.5);
567 videotl_label.set_padding (5,0);
568 videotl_label.hide();
569 videotl_label.set_no_show_all();
571 range_mark_label.set_name ("EditorRulerLabel");
572 range_mark_label.set_size_request (-1, (int)timebar_height);
573 range_mark_label.set_alignment (1.0, 0.5);
574 range_mark_label.set_padding (5,0);
575 range_mark_label.hide();
576 range_mark_label.set_no_show_all();
578 transport_mark_label.set_name ("EditorRulerLabel");
579 transport_mark_label.set_size_request (-1, (int)timebar_height);
580 transport_mark_label.set_alignment (1.0, 0.5);
581 transport_mark_label.set_padding (5,0);
582 transport_mark_label.hide();
583 transport_mark_label.set_no_show_all();
585 initialize_canvas ();
587 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
589 _summary = new EditorSummary (this);
591 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
592 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
594 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
596 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
597 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
599 edit_controls_vbox.set_spacing (0);
600 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
601 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
603 HBox* h = manage (new HBox);
604 _group_tabs = new EditorGroupTabs (this);
605 if (!ARDOUR::Profile->get_trx()) {
606 h->pack_start (*_group_tabs, PACK_SHRINK);
608 h->pack_start (edit_controls_vbox);
609 controls_layout.add (*h);
611 controls_layout.set_name ("EditControlsBase");
612 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
613 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
614 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
616 _cursors = new MouseCursors;
617 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
618 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
620 /* Push default cursor to ever-present bottom of cursor stack. */
621 push_canvas_cursor(_cursors->grabber);
623 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
625 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
626 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
627 pad_line_1->set_outline_color (0xFF0000FF);
633 edit_packer.set_col_spacings (0);
634 edit_packer.set_row_spacings (0);
635 edit_packer.set_homogeneous (false);
636 edit_packer.set_border_width (0);
637 edit_packer.set_name ("EditorWindow");
639 time_bars_event_box.add (time_bars_vbox);
640 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
641 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
643 /* labels for the time bars */
644 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
646 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
648 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
650 bottom_hbox.set_border_width (2);
651 bottom_hbox.set_spacing (3);
653 _route_groups = new EditorRouteGroups (this);
654 _routes = new EditorRoutes (this);
655 _regions = new EditorRegions (this);
656 _snapshots = new EditorSnapshots (this);
657 _locations = new EditorLocations (this);
659 /* these are static location signals */
661 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
662 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
663 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
665 add_notebook_page (_("Regions"), _regions->widget ());
666 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
667 add_notebook_page (_("Snapshots"), _snapshots->widget ());
668 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
669 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
671 _the_notebook.set_show_tabs (true);
672 _the_notebook.set_scrollable (true);
673 _the_notebook.popup_disable ();
674 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
675 _the_notebook.show_all ();
677 _notebook_shrunk = false;
679 editor_summary_pane.pack1(edit_packer);
681 Button* summary_arrows_left_left = manage (new Button);
682 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
683 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
684 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
686 Button* summary_arrows_left_right = manage (new Button);
687 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
688 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
689 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
691 VBox* summary_arrows_left = manage (new VBox);
692 summary_arrows_left->pack_start (*summary_arrows_left_left);
693 summary_arrows_left->pack_start (*summary_arrows_left_right);
695 Button* summary_arrows_right_up = manage (new Button);
696 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
697 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
698 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
700 Button* summary_arrows_right_down = manage (new Button);
701 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
702 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
703 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
705 VBox* summary_arrows_right = manage (new VBox);
706 summary_arrows_right->pack_start (*summary_arrows_right_up);
707 summary_arrows_right->pack_start (*summary_arrows_right_down);
709 Frame* summary_frame = manage (new Frame);
710 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
712 summary_frame->add (*_summary);
713 summary_frame->show ();
715 _summary_hbox.pack_start (*summary_arrows_left, false, false);
716 _summary_hbox.pack_start (*summary_frame, true, true);
717 _summary_hbox.pack_start (*summary_arrows_right, false, false);
719 if (!ARDOUR::Profile->get_trx()) {
720 editor_summary_pane.pack2 (_summary_hbox);
723 edit_pane.pack1 (editor_summary_pane, true, true);
724 if (!ARDOUR::Profile->get_trx()) {
725 edit_pane.pack2 (_the_notebook, false, true);
728 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
730 /* XXX: editor_summary_pane might need similar to the edit_pane */
732 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
734 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
735 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
737 top_hbox.pack_start (toolbar_frame);
739 HBox *hbox = manage (new HBox);
740 hbox->pack_start (edit_pane, true, true);
742 global_vpacker.pack_start (top_hbox, false, false);
743 global_vpacker.pack_start (*hbox, true, true);
744 global_hpacker.pack_start (global_vpacker, true, true);
746 /* need to show the "contents" widget so that notebook will show if tab is switched to
749 global_hpacker.show ();
751 /* register actions now so that set_state() can find them and set toggles/checks etc */
758 _playlist_selector = new PlaylistSelector();
759 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
761 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
765 nudge_forward_button.set_name ("nudge button");
766 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
768 nudge_backward_button.set_name ("nudge button");
769 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
771 fade_context_menu.set_name ("ArdourContextMenu");
773 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
775 /* allow external control surfaces/protocols to do various things */
777 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
778 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
779 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
780 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
781 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
782 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
783 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
784 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
785 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
786 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
787 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
788 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
789 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
790 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
792 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
793 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
794 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
795 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
796 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
798 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
800 /* problematic: has to return a value and thus cannot be x-thread */
802 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
804 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
805 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
807 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
809 _ignore_region_action = false;
810 _last_region_menu_was_main = false;
811 _popup_region_menu_item = 0;
813 _ignore_follow_edits = false;
815 _show_marker_lines = false;
817 /* Button bindings */
819 button_bindings = new Bindings ("editor-mouse");
821 XMLNode* node = button_settings();
823 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
824 button_bindings->load_operation (**i);
830 /* grab current parameter state */
831 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
832 UIConfiguration::instance().map_parameters (pc);
834 setup_fade_images ();
836 LuaInstance::instance(); // instantiate
837 LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &Editor::set_script_action_name));
844 delete button_bindings;
846 delete _route_groups;
847 delete _track_canvas_viewport;
850 delete quantize_dialog;
856 delete _playlist_selector;
858 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
864 Editor::button_settings () const
866 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
867 XMLNode* node = find_named_node (*settings, X_("Buttons"));
870 node = new XMLNode (X_("Buttons"));
877 Editor::get_smart_mode () const
879 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
883 Editor::catch_vanishing_regionview (RegionView *rv)
885 /* note: the selection will take care of the vanishing
886 audioregionview by itself.
889 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
893 if (clicked_regionview == rv) {
894 clicked_regionview = 0;
897 if (entered_regionview == rv) {
898 set_entered_regionview (0);
901 if (!_all_region_actions_sensitized) {
902 sensitize_all_region_actions (true);
907 Editor::set_entered_regionview (RegionView* rv)
909 if (rv == entered_regionview) {
913 if (entered_regionview) {
914 entered_regionview->exited ();
917 entered_regionview = rv;
919 if (entered_regionview != 0) {
920 entered_regionview->entered ();
923 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
924 /* This RegionView entry might have changed what region actions
925 are allowed, so sensitize them all in case a key is pressed.
927 sensitize_all_region_actions (true);
932 Editor::set_entered_track (TimeAxisView* tav)
935 entered_track->exited ();
941 entered_track->entered ();
946 Editor::instant_save ()
948 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
953 _session->add_instant_xml(get_state());
955 Config->add_instant_xml(get_state());
960 Editor::control_vertical_zoom_in_all ()
962 tav_zoom_smooth (false, true);
966 Editor::control_vertical_zoom_out_all ()
968 tav_zoom_smooth (true, true);
972 Editor::control_vertical_zoom_in_selected ()
974 tav_zoom_smooth (false, false);
978 Editor::control_vertical_zoom_out_selected ()
980 tav_zoom_smooth (true, false);
984 Editor::control_view (uint32_t view)
986 goto_visual_state (view);
990 Editor::control_unselect ()
992 selection->clear_tracks ();
996 Editor::control_select (uint32_t rid, Selection::Operation op)
998 /* handles the (static) signal from the ControlProtocol class that
999 * requests setting the selected track to a given RID
1006 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1012 TimeAxisView* tav = axis_view_from_route (r);
1016 case Selection::Add:
1017 selection->add (tav);
1019 case Selection::Toggle:
1020 selection->toggle (tav);
1022 case Selection::Extend:
1024 case Selection::Set:
1025 selection->set (tav);
1029 selection->clear_tracks ();
1034 Editor::control_step_tracks_up ()
1036 scroll_tracks_up_line ();
1040 Editor::control_step_tracks_down ()
1042 scroll_tracks_down_line ();
1046 Editor::control_scroll (float fraction)
1048 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1054 double step = fraction * current_page_samples();
1057 _control_scroll_target is an optional<T>
1059 it acts like a pointer to an framepos_t, with
1060 a operator conversion to boolean to check
1061 that it has a value could possibly use
1062 playhead_cursor->current_frame to store the
1063 value and a boolean in the class to know
1064 when it's out of date
1067 if (!_control_scroll_target) {
1068 _control_scroll_target = _session->transport_frame();
1069 _dragging_playhead = true;
1072 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1073 *_control_scroll_target = 0;
1074 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1075 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1077 *_control_scroll_target += (framepos_t) trunc (step);
1080 /* move visuals, we'll catch up with it later */
1082 playhead_cursor->set_position (*_control_scroll_target);
1083 UpdateAllTransportClocks (*_control_scroll_target);
1085 if (*_control_scroll_target > (current_page_samples() / 2)) {
1086 /* try to center PH in window */
1087 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1093 Now we do a timeout to actually bring the session to the right place
1094 according to the playhead. This is to avoid reading disk buffers on every
1095 call to control_scroll, which is driven by ScrollTimeline and therefore
1096 probably by a control surface wheel which can generate lots of events.
1098 /* cancel the existing timeout */
1100 control_scroll_connection.disconnect ();
1102 /* add the next timeout */
1104 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1108 Editor::deferred_control_scroll (framepos_t /*target*/)
1110 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1111 // reset for next stream
1112 _control_scroll_target = boost::none;
1113 _dragging_playhead = false;
1118 Editor::access_action (std::string action_group, std::string action_item)
1124 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1127 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1135 Editor::on_realize ()
1139 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1140 start_lock_event_timing ();
1145 Editor::start_lock_event_timing ()
1147 /* check if we should lock the GUI every 30 seconds */
1149 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1153 Editor::generic_event_handler (GdkEvent* ev)
1156 case GDK_BUTTON_PRESS:
1157 case GDK_BUTTON_RELEASE:
1158 case GDK_MOTION_NOTIFY:
1160 case GDK_KEY_RELEASE:
1161 if (contents().is_mapped()) {
1162 gettimeofday (&last_event_time, 0);
1166 case GDK_LEAVE_NOTIFY:
1167 switch (ev->crossing.detail) {
1168 case GDK_NOTIFY_UNKNOWN:
1169 case GDK_NOTIFY_INFERIOR:
1170 case GDK_NOTIFY_ANCESTOR:
1172 case GDK_NOTIFY_VIRTUAL:
1173 case GDK_NOTIFY_NONLINEAR:
1174 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1175 /* leaving window, so reset focus, thus ending any and
1176 all text entry operations.
1191 Editor::lock_timeout_callback ()
1193 struct timeval now, delta;
1195 gettimeofday (&now, 0);
1197 timersub (&now, &last_event_time, &delta);
1199 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1201 /* don't call again. Returning false will effectively
1202 disconnect us from the timer callback.
1204 unlock() will call start_lock_event_timing() to get things
1214 Editor::map_position_change (framepos_t frame)
1216 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1218 if (_session == 0) {
1222 if (_follow_playhead) {
1223 center_screen (frame);
1226 playhead_cursor->set_position (frame);
1230 Editor::center_screen (framepos_t frame)
1232 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1234 /* if we're off the page, then scroll.
1237 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1238 center_screen_internal (frame, page);
1243 Editor::center_screen_internal (framepos_t frame, float page)
1248 frame -= (framepos_t) page;
1253 reset_x_origin (frame);
1258 Editor::update_title ()
1260 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1262 if (!own_window()) {
1267 bool dirty = _session->dirty();
1269 string session_name;
1271 if (_session->snap_name() != _session->name()) {
1272 session_name = _session->snap_name();
1274 session_name = _session->name();
1278 session_name = "*" + session_name;
1281 WindowTitle title(session_name);
1282 title += S_("Window|Editor");
1283 title += Glib::get_application_name();
1284 own_window()->set_title (title.get_string());
1286 /* ::session_going_away() will have taken care of it */
1291 Editor::set_session (Session *t)
1293 SessionHandlePtr::set_session (t);
1299 _playlist_selector->set_session (_session);
1300 nudge_clock->set_session (_session);
1301 _summary->set_session (_session);
1302 _group_tabs->set_session (_session);
1303 _route_groups->set_session (_session);
1304 _regions->set_session (_session);
1305 _snapshots->set_session (_session);
1306 _routes->set_session (_session);
1307 _locations->set_session (_session);
1309 if (rhythm_ferret) {
1310 rhythm_ferret->set_session (_session);
1313 if (analysis_window) {
1314 analysis_window->set_session (_session);
1318 sfbrowser->set_session (_session);
1321 compute_fixed_ruler_scale ();
1323 /* Make sure we have auto loop and auto punch ranges */
1325 Location* loc = _session->locations()->auto_loop_location();
1327 loc->set_name (_("Loop"));
1330 loc = _session->locations()->auto_punch_location();
1333 loc->set_name (_("Punch"));
1336 refresh_location_display ();
1338 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1339 the selected Marker; this needs the LocationMarker list to be available.
1341 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1342 set_state (*node, Stateful::loading_state_version);
1344 /* catch up with the playhead */
1346 _session->request_locate (playhead_cursor->current_frame ());
1347 _pending_initial_locate = true;
1351 /* These signals can all be emitted by a non-GUI thread. Therefore the
1352 handlers for them must not attempt to directly interact with the GUI,
1353 but use PBD::Signal<T>::connect() which accepts an event loop
1354 ("context") where the handler will be asked to run.
1357 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1358 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1359 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1360 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1361 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1362 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1363 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1364 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1365 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1366 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1367 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1368 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1369 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1371 playhead_cursor->show ();
1373 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1374 Config->map_parameters (pc);
1375 _session->config.map_parameters (pc);
1377 restore_ruler_visibility ();
1378 //tempo_map_changed (PropertyChange (0));
1379 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1381 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1382 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1385 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1386 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1389 switch (_snap_type) {
1390 case SnapToRegionStart:
1391 case SnapToRegionEnd:
1392 case SnapToRegionSync:
1393 case SnapToRegionBoundary:
1394 build_region_boundary_cache ();
1401 /* register for undo history */
1402 _session->register_with_memento_command_factory(id(), this);
1403 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1405 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1407 LuaInstance::instance()->set_session(_session);
1409 start_updating_meters ();
1413 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1415 if (a->get_name() == "RegionMenu") {
1416 /* When the main menu's region menu is opened, we setup the actions so that they look right
1417 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1418 so we resensitize all region actions when the entered regionview or the region selection
1419 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1420 happens after the region context menu is opened. So we set a flag here, too.
1424 sensitize_the_right_region_actions ();
1425 _last_region_menu_was_main = true;
1430 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1432 using namespace Menu_Helpers;
1434 void (Editor::*emf)(FadeShape);
1435 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1438 images = &_xfade_in_images;
1439 emf = &Editor::set_fade_in_shape;
1441 images = &_xfade_out_images;
1442 emf = &Editor::set_fade_out_shape;
1447 _("Linear (for highly correlated material)"),
1448 *(*images)[FadeLinear],
1449 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1453 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1457 _("Constant power"),
1458 *(*images)[FadeConstantPower],
1459 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1462 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1467 *(*images)[FadeSymmetric],
1468 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1472 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1477 *(*images)[FadeSlow],
1478 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1481 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1486 *(*images)[FadeFast],
1487 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1490 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1493 /** Pop up a context menu for when the user clicks on a start crossfade */
1495 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1497 using namespace Menu_Helpers;
1498 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1503 MenuList& items (xfade_in_context_menu.items());
1506 if (arv->audio_region()->fade_in_active()) {
1507 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1509 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1512 items.push_back (SeparatorElem());
1513 fill_xfade_menu (items, true);
1515 xfade_in_context_menu.popup (button, time);
1518 /** Pop up a context menu for when the user clicks on an end crossfade */
1520 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1522 using namespace Menu_Helpers;
1523 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1528 MenuList& items (xfade_out_context_menu.items());
1531 if (arv->audio_region()->fade_out_active()) {
1532 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1534 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1537 items.push_back (SeparatorElem());
1538 fill_xfade_menu (items, false);
1540 xfade_out_context_menu.popup (button, time);
1544 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1546 using namespace Menu_Helpers;
1547 Menu* (Editor::*build_menu_function)();
1550 switch (item_type) {
1552 case RegionViewName:
1553 case RegionViewNameHighlight:
1554 case LeftFrameHandle:
1555 case RightFrameHandle:
1556 if (with_selection) {
1557 build_menu_function = &Editor::build_track_selection_context_menu;
1559 build_menu_function = &Editor::build_track_region_context_menu;
1564 if (with_selection) {
1565 build_menu_function = &Editor::build_track_selection_context_menu;
1567 build_menu_function = &Editor::build_track_context_menu;
1572 if (clicked_routeview->track()) {
1573 build_menu_function = &Editor::build_track_context_menu;
1575 build_menu_function = &Editor::build_track_bus_context_menu;
1580 /* probably shouldn't happen but if it does, we don't care */
1584 menu = (this->*build_menu_function)();
1585 menu->set_name ("ArdourContextMenu");
1587 /* now handle specific situations */
1589 switch (item_type) {
1591 case RegionViewName:
1592 case RegionViewNameHighlight:
1593 case LeftFrameHandle:
1594 case RightFrameHandle:
1595 if (!with_selection) {
1596 if (region_edit_menu_split_item) {
1597 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1598 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1600 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1603 if (region_edit_menu_split_multichannel_item) {
1604 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1605 region_edit_menu_split_multichannel_item->set_sensitive (true);
1607 region_edit_menu_split_multichannel_item->set_sensitive (false);
1620 /* probably shouldn't happen but if it does, we don't care */
1624 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1626 /* Bounce to disk */
1628 using namespace Menu_Helpers;
1629 MenuList& edit_items = menu->items();
1631 edit_items.push_back (SeparatorElem());
1633 switch (clicked_routeview->audio_track()->freeze_state()) {
1634 case AudioTrack::NoFreeze:
1635 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1638 case AudioTrack::Frozen:
1639 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1642 case AudioTrack::UnFrozen:
1643 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1649 if (item_type == StreamItem && clicked_routeview) {
1650 clicked_routeview->build_underlay_menu(menu);
1653 /* When the region menu is opened, we setup the actions so that they look right
1656 sensitize_the_right_region_actions ();
1657 _last_region_menu_was_main = false;
1659 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1660 menu->popup (button, time);
1664 Editor::build_track_context_menu ()
1666 using namespace Menu_Helpers;
1668 MenuList& edit_items = track_context_menu.items();
1671 add_dstream_context_items (edit_items);
1672 return &track_context_menu;
1676 Editor::build_track_bus_context_menu ()
1678 using namespace Menu_Helpers;
1680 MenuList& edit_items = track_context_menu.items();
1683 add_bus_context_items (edit_items);
1684 return &track_context_menu;
1688 Editor::build_track_region_context_menu ()
1690 using namespace Menu_Helpers;
1691 MenuList& edit_items = track_region_context_menu.items();
1694 /* we've just cleared the track region context menu, so the menu that these
1695 two items were on will have disappeared; stop them dangling.
1697 region_edit_menu_split_item = 0;
1698 region_edit_menu_split_multichannel_item = 0;
1700 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1703 boost::shared_ptr<Track> tr;
1704 boost::shared_ptr<Playlist> pl;
1706 if ((tr = rtv->track())) {
1707 add_region_context_items (edit_items, tr);
1711 add_dstream_context_items (edit_items);
1713 return &track_region_context_menu;
1717 Editor::analyze_region_selection ()
1719 if (analysis_window == 0) {
1720 analysis_window = new AnalysisWindow();
1723 analysis_window->set_session(_session);
1725 analysis_window->show_all();
1728 analysis_window->set_regionmode();
1729 analysis_window->analyze();
1731 analysis_window->present();
1735 Editor::analyze_range_selection()
1737 if (analysis_window == 0) {
1738 analysis_window = new AnalysisWindow();
1741 analysis_window->set_session(_session);
1743 analysis_window->show_all();
1746 analysis_window->set_rangemode();
1747 analysis_window->analyze();
1749 analysis_window->present();
1753 Editor::build_track_selection_context_menu ()
1755 using namespace Menu_Helpers;
1756 MenuList& edit_items = track_selection_context_menu.items();
1757 edit_items.clear ();
1759 add_selection_context_items (edit_items);
1760 // edit_items.push_back (SeparatorElem());
1761 // add_dstream_context_items (edit_items);
1763 return &track_selection_context_menu;
1767 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1769 using namespace Menu_Helpers;
1771 /* OK, stick the region submenu at the top of the list, and then add
1775 RegionSelection rs = get_regions_from_selection_and_entered ();
1777 string::size_type pos = 0;
1778 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1780 /* we have to hack up the region name because "_" has a special
1781 meaning for menu titles.
1784 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1785 menu_item_name.replace (pos, 1, "__");
1789 if (_popup_region_menu_item == 0) {
1790 _popup_region_menu_item = new MenuItem (menu_item_name);
1791 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1792 _popup_region_menu_item->show ();
1794 _popup_region_menu_item->set_label (menu_item_name);
1797 /* No latering allowed in later is higher layering model */
1798 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1799 if (act && Config->get_layer_model() == LaterHigher) {
1800 act->set_sensitive (false);
1802 act->set_sensitive (true);
1805 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1807 edit_items.push_back (*_popup_region_menu_item);
1808 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1809 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1811 edit_items.push_back (SeparatorElem());
1814 /** Add context menu items relevant to selection ranges.
1815 * @param edit_items List to add the items to.
1818 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1820 using namespace Menu_Helpers;
1822 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1823 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1825 edit_items.push_back (SeparatorElem());
1826 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1828 edit_items.push_back (SeparatorElem());
1829 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1831 edit_items.push_back (SeparatorElem());
1833 edit_items.push_back (
1835 _("Move Range Start to Previous Region Boundary"),
1836 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1840 edit_items.push_back (
1842 _("Move Range Start to Next Region Boundary"),
1843 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1847 edit_items.push_back (
1849 _("Move Range End to Previous Region Boundary"),
1850 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1854 edit_items.push_back (
1856 _("Move Range End to Next Region Boundary"),
1857 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1861 edit_items.push_back (SeparatorElem());
1862 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1863 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1865 edit_items.push_back (SeparatorElem());
1866 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1868 edit_items.push_back (SeparatorElem());
1869 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1870 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1871 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1873 edit_items.push_back (SeparatorElem());
1874 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1876 edit_items.push_back (SeparatorElem());
1877 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1878 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1880 edit_items.push_back (SeparatorElem());
1881 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1882 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1883 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1884 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1885 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1886 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1887 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1893 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1895 using namespace Menu_Helpers;
1899 Menu *play_menu = manage (new Menu);
1900 MenuList& play_items = play_menu->items();
1901 play_menu->set_name ("ArdourContextMenu");
1903 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1904 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1905 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1906 play_items.push_back (SeparatorElem());
1907 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1909 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1913 Menu *select_menu = manage (new Menu);
1914 MenuList& select_items = select_menu->items();
1915 select_menu->set_name ("ArdourContextMenu");
1917 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1918 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1919 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1920 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1921 select_items.push_back (SeparatorElem());
1922 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1923 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1924 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
1925 select_items.push_back (SeparatorElem());
1926 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
1927 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
1928 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1929 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1930 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1931 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1932 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1934 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1938 Menu *cutnpaste_menu = manage (new Menu);
1939 MenuList& cutnpaste_items = cutnpaste_menu->items();
1940 cutnpaste_menu->set_name ("ArdourContextMenu");
1942 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1943 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1944 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1946 cutnpaste_items.push_back (SeparatorElem());
1948 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1949 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1951 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1953 /* Adding new material */
1955 edit_items.push_back (SeparatorElem());
1956 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1957 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1961 Menu *nudge_menu = manage (new Menu());
1962 MenuList& nudge_items = nudge_menu->items();
1963 nudge_menu->set_name ("ArdourContextMenu");
1965 edit_items.push_back (SeparatorElem());
1966 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1967 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1968 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1969 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1971 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1975 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1977 using namespace Menu_Helpers;
1981 Menu *play_menu = manage (new Menu);
1982 MenuList& play_items = play_menu->items();
1983 play_menu->set_name ("ArdourContextMenu");
1985 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1986 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1987 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1991 Menu *select_menu = manage (new Menu);
1992 MenuList& select_items = select_menu->items();
1993 select_menu->set_name ("ArdourContextMenu");
1995 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1996 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1997 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1998 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1999 select_items.push_back (SeparatorElem());
2000 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2001 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2002 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2003 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2005 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2009 Menu *cutnpaste_menu = manage (new Menu);
2010 MenuList& cutnpaste_items = cutnpaste_menu->items();
2011 cutnpaste_menu->set_name ("ArdourContextMenu");
2013 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2014 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2015 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2017 Menu *nudge_menu = manage (new Menu());
2018 MenuList& nudge_items = nudge_menu->items();
2019 nudge_menu->set_name ("ArdourContextMenu");
2021 edit_items.push_back (SeparatorElem());
2022 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2023 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2024 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2025 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2027 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2031 Editor::snap_type() const
2037 Editor::snap_mode() const
2043 Editor::set_snap_to (SnapType st)
2045 unsigned int snap_ind = (unsigned int)st;
2047 if (internal_editing()) {
2048 internal_snap_type = st;
2050 pre_internal_snap_type = st;
2055 if (snap_ind > snap_type_strings.size() - 1) {
2057 _snap_type = (SnapType)snap_ind;
2060 string str = snap_type_strings[snap_ind];
2062 if (str != snap_type_selector.get_text()) {
2063 snap_type_selector.set_text (str);
2068 switch (_snap_type) {
2069 case SnapToBeatDiv128:
2070 case SnapToBeatDiv64:
2071 case SnapToBeatDiv32:
2072 case SnapToBeatDiv28:
2073 case SnapToBeatDiv24:
2074 case SnapToBeatDiv20:
2075 case SnapToBeatDiv16:
2076 case SnapToBeatDiv14:
2077 case SnapToBeatDiv12:
2078 case SnapToBeatDiv10:
2079 case SnapToBeatDiv8:
2080 case SnapToBeatDiv7:
2081 case SnapToBeatDiv6:
2082 case SnapToBeatDiv5:
2083 case SnapToBeatDiv4:
2084 case SnapToBeatDiv3:
2085 case SnapToBeatDiv2: {
2086 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2087 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2089 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2090 current_bbt_points_begin, current_bbt_points_end);
2091 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2092 current_bbt_points_begin, current_bbt_points_end);
2093 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2097 case SnapToRegionStart:
2098 case SnapToRegionEnd:
2099 case SnapToRegionSync:
2100 case SnapToRegionBoundary:
2101 build_region_boundary_cache ();
2109 redisplay_tempo (false);
2111 SnapChanged (); /* EMIT SIGNAL */
2115 Editor::set_snap_mode (SnapMode mode)
2117 string str = snap_mode_strings[(int)mode];
2119 if (internal_editing()) {
2120 internal_snap_mode = mode;
2122 pre_internal_snap_mode = mode;
2127 if (str != snap_mode_selector.get_text ()) {
2128 snap_mode_selector.set_text (str);
2135 Editor::set_edit_point_preference (EditPoint ep, bool force)
2137 bool changed = (_edit_point != ep);
2140 if (Profile->get_mixbus())
2141 if (ep == EditAtSelectedMarker)
2142 ep = EditAtPlayhead;
2144 string str = edit_point_strings[(int)ep];
2145 if (str != edit_point_selector.get_text ()) {
2146 edit_point_selector.set_text (str);
2149 update_all_enter_cursors();
2151 if (!force && !changed) {
2155 const char* action=NULL;
2157 switch (_edit_point) {
2158 case EditAtPlayhead:
2159 action = "edit-at-playhead";
2161 case EditAtSelectedMarker:
2162 action = "edit-at-marker";
2165 action = "edit-at-mouse";
2169 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2171 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2175 bool in_track_canvas;
2177 if (!mouse_frame (foo, in_track_canvas)) {
2178 in_track_canvas = false;
2181 reset_canvas_action_sensitivity (in_track_canvas);
2187 Editor::set_state (const XMLNode& node, int version)
2189 const XMLProperty* prop;
2192 Tabbable::set_state (node, version);
2194 if (_session && (prop = node.property ("playhead"))) {
2196 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2198 playhead_cursor->set_position (pos);
2200 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2201 playhead_cursor->set_position (0);
2204 playhead_cursor->set_position (0);
2207 if ((prop = node.property ("mixer-width"))) {
2208 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2211 if ((prop = node.property ("zoom-focus"))) {
2212 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2215 if ((prop = node.property ("zoom"))) {
2216 /* older versions of ardour used floating point samples_per_pixel */
2217 double f = PBD::atof (prop->value());
2218 reset_zoom (llrintf (f));
2220 reset_zoom (samples_per_pixel);
2223 if ((prop = node.property ("visible-track-count"))) {
2224 set_visible_track_count (PBD::atoi (prop->value()));
2227 if ((prop = node.property ("snap-to"))) {
2228 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2231 if ((prop = node.property ("snap-mode"))) {
2232 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2235 if ((prop = node.property ("internal-snap-to"))) {
2236 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2239 if ((prop = node.property ("internal-snap-mode"))) {
2240 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2243 if ((prop = node.property ("pre-internal-snap-to"))) {
2244 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2247 if ((prop = node.property ("pre-internal-snap-mode"))) {
2248 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2251 if ((prop = node.property ("mouse-mode"))) {
2252 MouseMode m = str2mousemode(prop->value());
2253 set_mouse_mode (m, true);
2255 set_mouse_mode (MouseObject, true);
2258 if ((prop = node.property ("left-frame")) != 0) {
2260 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2264 reset_x_origin (pos);
2268 if ((prop = node.property ("y-origin")) != 0) {
2269 reset_y_origin (atof (prop->value ()));
2272 if ((prop = node.property ("join-object-range"))) {
2273 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2274 bool yn = string_is_affirmative (prop->value());
2276 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2277 tact->set_active (!yn);
2278 tact->set_active (yn);
2280 set_mouse_mode(mouse_mode, true);
2283 if ((prop = node.property ("edit-point"))) {
2284 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2287 if ((prop = node.property ("show-measures"))) {
2288 bool yn = string_is_affirmative (prop->value());
2289 _show_measures = yn;
2292 if ((prop = node.property ("follow-playhead"))) {
2293 bool yn = string_is_affirmative (prop->value());
2294 set_follow_playhead (yn);
2297 if ((prop = node.property ("stationary-playhead"))) {
2298 bool yn = string_is_affirmative (prop->value());
2299 set_stationary_playhead (yn);
2302 if ((prop = node.property ("region-list-sort-type"))) {
2303 RegionListSortType st;
2304 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2307 if ((prop = node.property ("show-editor-mixer"))) {
2309 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2312 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2313 bool yn = string_is_affirmative (prop->value());
2315 /* do it twice to force the change */
2317 tact->set_active (!yn);
2318 tact->set_active (yn);
2321 if ((prop = node.property ("show-editor-list"))) {
2323 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2326 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2327 bool yn = string_is_affirmative (prop->value());
2329 /* do it twice to force the change */
2331 tact->set_active (!yn);
2332 tact->set_active (yn);
2335 if ((prop = node.property (X_("editor-list-page")))) {
2336 _the_notebook.set_current_page (atoi (prop->value ()));
2339 if ((prop = node.property (X_("show-marker-lines")))) {
2340 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2342 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2343 bool yn = string_is_affirmative (prop->value ());
2345 tact->set_active (!yn);
2346 tact->set_active (yn);
2349 XMLNodeList children = node.children ();
2350 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2351 selection->set_state (**i, Stateful::current_state_version);
2352 _regions->set_state (**i);
2355 if ((prop = node.property ("maximised"))) {
2356 bool yn = string_is_affirmative (prop->value());
2357 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2359 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2360 bool fs = tact && tact->get_active();
2362 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2366 if ((prop = node.property ("nudge-clock-value"))) {
2368 sscanf (prop->value().c_str(), "%" PRId64, &f);
2369 nudge_clock->set (f);
2371 nudge_clock->set_mode (AudioClock::Timecode);
2372 nudge_clock->set (_session->frame_rate() * 5, true);
2377 * Not all properties may have been in XML, but
2378 * those that are linked to a private variable may need changing
2383 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2385 yn = _show_measures;
2386 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2387 /* do it twice to force the change */
2388 tact->set_active (!yn);
2389 tact->set_active (yn);
2392 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2393 yn = _follow_playhead;
2395 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2396 if (tact->get_active() != yn) {
2397 tact->set_active (yn);
2401 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2402 yn = _stationary_playhead;
2404 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2405 if (tact->get_active() != yn) {
2406 tact->set_active (yn);
2411 return LuaInstance::instance()->set_state(node);
2415 Editor::get_state ()
2417 XMLNode* node = new XMLNode (X_("Editor"));
2420 id().print (buf, sizeof (buf));
2421 node->add_property ("id", buf);
2423 node->add_child_nocopy (Tabbable::get_state());
2425 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2426 node->add_property("edit-horizontal-pane-pos", string(buf));
2427 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2428 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2429 node->add_property("edit-vertical-pane-pos", string(buf));
2431 maybe_add_mixer_strip_width (*node);
2433 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2435 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2436 node->add_property ("zoom", buf);
2437 node->add_property ("snap-to", enum_2_string (_snap_type));
2438 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2439 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2440 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2441 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2442 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2443 node->add_property ("edit-point", enum_2_string (_edit_point));
2444 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2445 node->add_property ("visible-track-count", buf);
2447 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2448 node->add_property ("playhead", buf);
2449 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2450 node->add_property ("left-frame", buf);
2451 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2452 node->add_property ("y-origin", buf);
2454 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2455 node->add_property ("maximised", _maximised ? "yes" : "no");
2456 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2457 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2458 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2459 node->add_property ("mouse-mode", enum2str(mouse_mode));
2460 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2462 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2464 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2465 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2468 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2470 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2471 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2474 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2475 node->add_property (X_("editor-list-page"), buf);
2477 if (button_bindings) {
2478 XMLNode* bb = new XMLNode (X_("Buttons"));
2479 button_bindings->save (*bb);
2480 node->add_child_nocopy (*bb);
2483 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2485 node->add_child_nocopy (selection->get_state ());
2486 node->add_child_nocopy (_regions->get_state ());
2488 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2489 node->add_property ("nudge-clock-value", buf);
2491 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2492 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2497 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2498 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2500 * @return pair: TimeAxisView that y is over, layer index.
2502 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2503 * in stacked or expanded region display mode, otherwise 0.
2505 std::pair<TimeAxisView *, double>
2506 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2508 if (!trackview_relative_offset) {
2509 y -= _trackview_group->canvas_origin().y;
2513 return std::make_pair ( (TimeAxisView *) 0, 0);
2516 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2518 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2525 return std::make_pair ( (TimeAxisView *) 0, 0);
2528 /** Snap a position to the grid, if appropriate, taking into account current
2529 * grid settings and also the state of any snap modifier keys that may be pressed.
2530 * @param start Position to snap.
2531 * @param event Event to get current key modifier information from, or 0.
2534 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2536 if (!_session || !event) {
2540 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2541 if (_snap_mode == SnapOff) {
2542 snap_to_internal (start, direction, for_mark);
2545 if (_snap_mode != SnapOff) {
2546 snap_to_internal (start, direction, for_mark);
2547 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2548 /* SnapOff, but we pressed the snap_delta modifier */
2549 snap_to_internal (start, direction, for_mark);
2555 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2557 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2561 snap_to_internal (start, direction, for_mark, ensure_snap);
2565 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2567 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2568 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2570 switch (_snap_type) {
2571 case SnapToTimecodeFrame:
2572 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2573 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2574 /* start is already on a whole timecode frame, do nothing */
2575 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2576 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2578 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2582 case SnapToTimecodeSeconds:
2583 if (_session->config.get_timecode_offset_negative()) {
2584 start += _session->config.get_timecode_offset ();
2586 start -= _session->config.get_timecode_offset ();
2588 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2589 (start % one_timecode_second == 0)) {
2590 /* start is already on a whole second, do nothing */
2591 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2592 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2594 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2597 if (_session->config.get_timecode_offset_negative()) {
2598 start -= _session->config.get_timecode_offset ();
2600 start += _session->config.get_timecode_offset ();
2604 case SnapToTimecodeMinutes:
2605 if (_session->config.get_timecode_offset_negative()) {
2606 start += _session->config.get_timecode_offset ();
2608 start -= _session->config.get_timecode_offset ();
2610 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2611 (start % one_timecode_minute == 0)) {
2612 /* start is already on a whole minute, do nothing */
2613 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2614 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2616 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2618 if (_session->config.get_timecode_offset_negative()) {
2619 start -= _session->config.get_timecode_offset ();
2621 start += _session->config.get_timecode_offset ();
2625 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2626 abort(); /*NOTREACHED*/
2631 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2633 const framepos_t one_second = _session->frame_rate();
2634 const framepos_t one_minute = _session->frame_rate() * 60;
2635 framepos_t presnap = start;
2639 switch (_snap_type) {
2640 case SnapToTimecodeFrame:
2641 case SnapToTimecodeSeconds:
2642 case SnapToTimecodeMinutes:
2643 return timecode_snap_to_internal (start, direction, for_mark);
2646 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2647 start % (one_second/75) == 0) {
2648 /* start is already on a whole CD frame, do nothing */
2649 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2650 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2652 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2657 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2658 start % one_second == 0) {
2659 /* start is already on a whole second, do nothing */
2660 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2661 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2663 start = (framepos_t) floor ((double) start / one_second) * one_second;
2668 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2669 start % one_minute == 0) {
2670 /* start is already on a whole minute, do nothing */
2671 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2672 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2674 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2679 start = _session->tempo_map().round_to_bar (start, direction);
2683 start = _session->tempo_map().round_to_beat (start, direction);
2686 case SnapToBeatDiv128:
2687 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2689 case SnapToBeatDiv64:
2690 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2692 case SnapToBeatDiv32:
2693 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2695 case SnapToBeatDiv28:
2696 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2698 case SnapToBeatDiv24:
2699 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2701 case SnapToBeatDiv20:
2702 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2704 case SnapToBeatDiv16:
2705 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2707 case SnapToBeatDiv14:
2708 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2710 case SnapToBeatDiv12:
2711 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2713 case SnapToBeatDiv10:
2714 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2716 case SnapToBeatDiv8:
2717 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2719 case SnapToBeatDiv7:
2720 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2722 case SnapToBeatDiv6:
2723 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2725 case SnapToBeatDiv5:
2726 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2728 case SnapToBeatDiv4:
2729 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2731 case SnapToBeatDiv3:
2732 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2734 case SnapToBeatDiv2:
2735 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2743 _session->locations()->marks_either_side (start, before, after);
2745 if (before == max_framepos && after == max_framepos) {
2746 /* No marks to snap to, so just don't snap */
2748 } else if (before == max_framepos) {
2750 } else if (after == max_framepos) {
2752 } else if (before != max_framepos && after != max_framepos) {
2753 /* have before and after */
2754 if ((start - before) < (after - start)) {
2763 case SnapToRegionStart:
2764 case SnapToRegionEnd:
2765 case SnapToRegionSync:
2766 case SnapToRegionBoundary:
2767 if (!region_boundary_cache.empty()) {
2769 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2770 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2772 if (direction > 0) {
2773 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2775 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2778 if (next != region_boundary_cache.begin ()) {
2783 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2784 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2786 if (start > (p + n) / 2) {
2795 switch (_snap_mode) {
2805 if (presnap > start) {
2806 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2810 } else if (presnap < start) {
2811 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2817 /* handled at entry */
2825 Editor::setup_toolbar ()
2827 HBox* mode_box = manage(new HBox);
2828 mode_box->set_border_width (2);
2829 mode_box->set_spacing(2);
2831 HBox* mouse_mode_box = manage (new HBox);
2832 HBox* mouse_mode_hbox = manage (new HBox);
2833 VBox* mouse_mode_vbox = manage (new VBox);
2834 Alignment* mouse_mode_align = manage (new Alignment);
2836 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2837 mouse_mode_size_group->add_widget (smart_mode_button);
2838 mouse_mode_size_group->add_widget (mouse_move_button);
2839 mouse_mode_size_group->add_widget (mouse_cut_button);
2840 mouse_mode_size_group->add_widget (mouse_select_button);
2841 mouse_mode_size_group->add_widget (mouse_timefx_button);
2842 mouse_mode_size_group->add_widget (mouse_audition_button);
2843 mouse_mode_size_group->add_widget (mouse_draw_button);
2844 mouse_mode_size_group->add_widget (mouse_content_button);
2846 mouse_mode_size_group->add_widget (zoom_in_button);
2847 mouse_mode_size_group->add_widget (zoom_out_button);
2848 mouse_mode_size_group->add_widget (zoom_preset_selector);
2849 mouse_mode_size_group->add_widget (zoom_out_full_button);
2850 mouse_mode_size_group->add_widget (zoom_focus_selector);
2852 mouse_mode_size_group->add_widget (tav_shrink_button);
2853 mouse_mode_size_group->add_widget (tav_expand_button);
2854 mouse_mode_size_group->add_widget (visible_tracks_selector);
2856 mouse_mode_size_group->add_widget (snap_type_selector);
2857 mouse_mode_size_group->add_widget (snap_mode_selector);
2859 mouse_mode_size_group->add_widget (edit_point_selector);
2860 mouse_mode_size_group->add_widget (edit_mode_selector);
2862 mouse_mode_size_group->add_widget (*nudge_clock);
2863 mouse_mode_size_group->add_widget (nudge_forward_button);
2864 mouse_mode_size_group->add_widget (nudge_backward_button);
2866 mouse_mode_hbox->set_spacing (2);
2868 if (!ARDOUR::Profile->get_trx()) {
2869 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2872 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2873 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2875 if (!ARDOUR::Profile->get_mixbus()) {
2876 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2879 if (!ARDOUR::Profile->get_trx()) {
2880 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2881 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2882 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2883 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2886 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2888 mouse_mode_align->add (*mouse_mode_vbox);
2889 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2891 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2893 edit_mode_selector.set_name ("mouse mode button");
2895 if (!ARDOUR::Profile->get_trx()) {
2896 mode_box->pack_start (edit_mode_selector, false, false);
2899 mode_box->pack_start (*mouse_mode_box, false, false);
2903 _zoom_box.set_spacing (2);
2904 _zoom_box.set_border_width (2);
2908 zoom_preset_selector.set_name ("zoom button");
2909 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2910 zoom_preset_selector.set_size_request (42, -1);
2912 zoom_in_button.set_name ("zoom button");
2913 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
2914 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2915 zoom_in_button.set_related_action (act);
2917 zoom_out_button.set_name ("zoom button");
2918 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
2919 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2920 zoom_out_button.set_related_action (act);
2922 zoom_out_full_button.set_name ("zoom button");
2923 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
2924 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2925 zoom_out_full_button.set_related_action (act);
2927 zoom_focus_selector.set_name ("zoom button");
2929 if (ARDOUR::Profile->get_mixbus()) {
2930 _zoom_box.pack_start (zoom_preset_selector, false, false);
2931 } else if (ARDOUR::Profile->get_trx()) {
2932 mode_box->pack_start (zoom_out_button, false, false);
2933 mode_box->pack_start (zoom_in_button, false, false);
2935 _zoom_box.pack_start (zoom_out_button, false, false);
2936 _zoom_box.pack_start (zoom_in_button, false, false);
2937 _zoom_box.pack_start (zoom_out_full_button, false, false);
2938 _zoom_box.pack_start (zoom_focus_selector, false, false);
2941 /* Track zoom buttons */
2942 visible_tracks_selector.set_name ("zoom button");
2943 if (Profile->get_mixbus()) {
2944 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2945 visible_tracks_selector.set_size_request (42, -1);
2947 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2950 tav_expand_button.set_name ("zoom button");
2951 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
2952 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2953 tav_expand_button.set_related_action (act);
2955 tav_shrink_button.set_name ("zoom button");
2956 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
2957 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2958 tav_shrink_button.set_related_action (act);
2960 if (ARDOUR::Profile->get_mixbus()) {
2961 _zoom_box.pack_start (visible_tracks_selector);
2962 } else if (ARDOUR::Profile->get_trx()) {
2963 _zoom_box.pack_start (tav_shrink_button);
2964 _zoom_box.pack_start (tav_expand_button);
2966 _zoom_box.pack_start (visible_tracks_selector);
2967 _zoom_box.pack_start (tav_shrink_button);
2968 _zoom_box.pack_start (tav_expand_button);
2971 snap_box.set_spacing (2);
2972 snap_box.set_border_width (2);
2974 snap_type_selector.set_name ("mouse mode button");
2976 snap_mode_selector.set_name ("mouse mode button");
2978 edit_point_selector.set_name ("mouse mode button");
2980 snap_box.pack_start (snap_mode_selector, false, false);
2981 snap_box.pack_start (snap_type_selector, false, false);
2982 snap_box.pack_start (edit_point_selector, false, false);
2986 HBox *nudge_box = manage (new HBox);
2987 nudge_box->set_spacing (2);
2988 nudge_box->set_border_width (2);
2990 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2991 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2993 nudge_box->pack_start (nudge_backward_button, false, false);
2994 nudge_box->pack_start (nudge_forward_button, false, false);
2995 nudge_box->pack_start (*nudge_clock, false, false);
2998 /* Pack everything in... */
3000 HBox* hbox = manage (new HBox);
3001 hbox->set_spacing(2);
3003 toolbar_hbox.set_spacing (2);
3004 toolbar_hbox.set_border_width (1);
3006 toolbar_hbox.pack_start (*mode_box, false, false);
3007 if (!ARDOUR::Profile->get_trx()) {
3008 toolbar_hbox.pack_start (_zoom_box, false, false);
3009 toolbar_hbox.pack_start (*hbox, false, false);
3012 if (!ARDOUR::Profile->get_trx()) {
3013 hbox->pack_start (snap_box, false, false);
3014 hbox->pack_start (*nudge_box, false, false);
3019 toolbar_base.set_name ("ToolBarBase");
3020 toolbar_base.add (toolbar_hbox);
3022 _toolbar_viewport.add (toolbar_base);
3023 /* stick to the required height but allow width to vary if there's not enough room */
3024 _toolbar_viewport.set_size_request (1, -1);
3026 toolbar_frame.set_shadow_type (SHADOW_OUT);
3027 toolbar_frame.set_name ("BaseFrame");
3028 toolbar_frame.add (_toolbar_viewport);
3032 Editor::build_edit_point_menu ()
3034 using namespace Menu_Helpers;
3036 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3037 if(!Profile->get_mixbus())
3038 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3039 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3041 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3045 Editor::build_edit_mode_menu ()
3047 using namespace Menu_Helpers;
3049 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3050 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3051 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3052 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3054 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3058 Editor::build_snap_mode_menu ()
3060 using namespace Menu_Helpers;
3062 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3063 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3064 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3066 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3070 Editor::build_snap_type_menu ()
3072 using namespace Menu_Helpers;
3074 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3075 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3076 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3077 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3078 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3079 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3080 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3081 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3082 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3083 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3084 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3085 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3086 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3087 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3088 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3089 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3090 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3091 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3092 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3093 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3094 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3095 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3096 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3097 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3098 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3099 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3100 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3101 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3102 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3103 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3105 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3110 Editor::setup_tooltips ()
3112 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3113 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3114 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3115 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3116 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3117 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3118 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3119 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3120 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3121 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3122 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3123 set_tooltip (zoom_in_button, _("Zoom In"));
3124 set_tooltip (zoom_out_button, _("Zoom Out"));
3125 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3126 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3127 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3128 set_tooltip (tav_expand_button, _("Expand Tracks"));
3129 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3130 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3131 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3132 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3133 set_tooltip (edit_point_selector, _("Edit Point"));
3134 set_tooltip (edit_mode_selector, _("Edit Mode"));
3135 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3139 Editor::convert_drop_to_paths (
3140 vector<string>& paths,
3141 const RefPtr<Gdk::DragContext>& /*context*/,
3144 const SelectionData& data,
3148 if (_session == 0) {
3152 vector<string> uris = data.get_uris();
3156 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3157 are actually URI lists. So do it by hand.
3160 if (data.get_target() != "text/plain") {
3164 /* Parse the "uri-list" format that Nautilus provides,
3165 where each pathname is delimited by \r\n.
3167 THERE MAY BE NO NULL TERMINATING CHAR!!!
3170 string txt = data.get_text();
3174 p = (char *) malloc (txt.length() + 1);
3175 txt.copy (p, txt.length(), 0);
3176 p[txt.length()] = '\0';
3182 while (g_ascii_isspace (*p))
3186 while (*q && (*q != '\n') && (*q != '\r')) {
3193 while (q > p && g_ascii_isspace (*q))
3198 uris.push_back (string (p, q - p + 1));
3202 p = strchr (p, '\n');
3214 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3215 if ((*i).substr (0,7) == "file://") {
3216 paths.push_back (Glib::filename_from_uri (*i));
3224 Editor::new_tempo_section ()
3229 Editor::map_transport_state ()
3231 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3233 if (_session && _session->transport_stopped()) {
3234 have_pending_keyboard_selection = false;
3237 update_loop_range_view ();
3243 Editor::begin_selection_op_history ()
3245 selection_op_cmd_depth = 0;
3246 selection_op_history_it = 0;
3248 while(!selection_op_history.empty()) {
3249 delete selection_op_history.front();
3250 selection_op_history.pop_front();
3253 selection_undo_action->set_sensitive (false);
3254 selection_redo_action->set_sensitive (false);
3255 selection_op_history.push_front (&_selection_memento->get_state ());
3259 Editor::begin_reversible_selection_op (string name)
3262 //cerr << name << endl;
3263 /* begin/commit pairs can be nested */
3264 selection_op_cmd_depth++;
3269 Editor::commit_reversible_selection_op ()
3272 if (selection_op_cmd_depth == 1) {
3274 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3276 The user has undone some selection ops and then made a new one,
3277 making anything earlier in the list invalid.
3280 list<XMLNode *>::iterator it = selection_op_history.begin();
3281 list<XMLNode *>::iterator e_it = it;
3282 advance (e_it, selection_op_history_it);
3284 for ( ; it != e_it; ++it) {
3287 selection_op_history.erase (selection_op_history.begin(), e_it);
3290 selection_op_history.push_front (&_selection_memento->get_state ());
3291 selection_op_history_it = 0;
3293 selection_undo_action->set_sensitive (true);
3294 selection_redo_action->set_sensitive (false);
3297 if (selection_op_cmd_depth > 0) {
3298 selection_op_cmd_depth--;
3304 Editor::undo_selection_op ()
3307 selection_op_history_it++;
3309 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3310 if (n == selection_op_history_it) {
3311 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3312 selection_redo_action->set_sensitive (true);
3316 /* is there an earlier entry? */
3317 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3318 selection_undo_action->set_sensitive (false);
3324 Editor::redo_selection_op ()
3327 if (selection_op_history_it > 0) {
3328 selection_op_history_it--;
3331 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3332 if (n == selection_op_history_it) {
3333 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3334 selection_undo_action->set_sensitive (true);
3339 if (selection_op_history_it == 0) {
3340 selection_redo_action->set_sensitive (false);
3346 Editor::begin_reversible_command (string name)
3349 before.push_back (&_selection_memento->get_state ());
3350 _session->begin_reversible_command (name);
3355 Editor::begin_reversible_command (GQuark q)
3358 before.push_back (&_selection_memento->get_state ());
3359 _session->begin_reversible_command (q);
3364 Editor::abort_reversible_command ()
3367 while(!before.empty()) {
3368 delete before.front();
3371 _session->abort_reversible_command ();
3376 Editor::commit_reversible_command ()
3379 if (before.size() == 1) {
3380 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3381 redo_action->set_sensitive(false);
3382 undo_action->set_sensitive(true);
3383 begin_selection_op_history ();
3386 if (before.empty()) {
3387 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3392 _session->commit_reversible_command ();
3397 Editor::history_changed ()
3401 if (undo_action && _session) {
3402 if (_session->undo_depth() == 0) {
3403 label = S_("Command|Undo");
3405 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3407 undo_action->property_label() = label;
3410 if (redo_action && _session) {
3411 if (_session->redo_depth() == 0) {
3413 redo_action->set_sensitive (false);
3415 label = string_compose(_("Redo (%1)"), _session->next_redo());
3416 redo_action->set_sensitive (true);
3418 redo_action->property_label() = label;
3423 Editor::duplicate_range (bool with_dialog)
3427 RegionSelection rs = get_regions_from_selection_and_entered ();
3429 if ( selection->time.length() == 0 && rs.empty()) {
3435 ArdourDialog win (_("Duplicate"));
3436 Label label (_("Number of duplications:"));
3437 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3438 SpinButton spinner (adjustment, 0.0, 1);
3441 win.get_vbox()->set_spacing (12);
3442 win.get_vbox()->pack_start (hbox);
3443 hbox.set_border_width (6);
3444 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3446 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3447 place, visually. so do this by hand.
3450 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3451 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3452 spinner.grab_focus();
3458 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3459 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3460 win.set_default_response (RESPONSE_ACCEPT);
3462 spinner.grab_focus ();
3464 switch (win.run ()) {
3465 case RESPONSE_ACCEPT:
3471 times = adjustment.get_value();
3474 if ((current_mouse_mode() == Editing::MouseRange)) {
3475 if (selection->time.length()) {
3476 duplicate_selection (times);
3478 } else if (get_smart_mode()) {
3479 if (selection->time.length()) {
3480 duplicate_selection (times);
3482 duplicate_some_regions (rs, times);
3484 duplicate_some_regions (rs, times);
3489 Editor::set_edit_mode (EditMode m)
3491 Config->set_edit_mode (m);
3495 Editor::cycle_edit_mode ()
3497 switch (Config->get_edit_mode()) {
3499 Config->set_edit_mode (Ripple);
3503 Config->set_edit_mode (Lock);
3506 Config->set_edit_mode (Slide);
3512 Editor::edit_mode_selection_done ( EditMode m )
3514 Config->set_edit_mode ( m );
3518 Editor::snap_type_selection_done (SnapType snaptype)
3520 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3522 ract->set_active ();
3527 Editor::snap_mode_selection_done (SnapMode mode)
3529 RefPtr<RadioAction> ract = snap_mode_action (mode);
3532 ract->set_active (true);
3537 Editor::cycle_edit_point (bool with_marker)
3539 if(Profile->get_mixbus())
3540 with_marker = false;
3542 switch (_edit_point) {
3544 set_edit_point_preference (EditAtPlayhead);
3546 case EditAtPlayhead:
3548 set_edit_point_preference (EditAtSelectedMarker);
3550 set_edit_point_preference (EditAtMouse);
3553 case EditAtSelectedMarker:
3554 set_edit_point_preference (EditAtMouse);
3560 Editor::edit_point_selection_done (EditPoint ep)
3562 set_edit_point_preference ( ep );
3566 Editor::build_zoom_focus_menu ()
3568 using namespace Menu_Helpers;
3570 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3571 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3572 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3573 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3574 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3575 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3577 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3581 Editor::zoom_focus_selection_done ( ZoomFocus f )
3583 RefPtr<RadioAction> ract = zoom_focus_action (f);
3585 ract->set_active ();
3590 Editor::build_track_count_menu ()
3592 using namespace Menu_Helpers;
3594 if (!Profile->get_mixbus()) {
3595 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3596 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3597 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3598 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3599 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3600 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3601 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3602 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3603 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3604 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3605 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3606 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3607 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3609 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3610 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3611 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3612 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3613 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3614 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3615 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3616 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3617 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3618 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3620 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3621 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3622 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3623 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3624 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3625 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3626 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3627 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3628 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3629 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3630 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3635 Editor::set_zoom_preset (int64_t ms)
3638 temporal_zoom_session();
3642 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3643 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3647 Editor::set_visible_track_count (int32_t n)
3649 _visible_track_count = n;
3651 /* if the canvas hasn't really been allocated any size yet, just
3652 record the desired number of visible tracks and return. when canvas
3653 allocation happens, we will get called again and then we can do the
3657 if (_visible_canvas_height <= 1) {
3663 DisplaySuspender ds;
3665 if (_visible_track_count > 0) {
3666 h = trackviews_height() / _visible_track_count;
3667 std::ostringstream s;
3668 s << _visible_track_count;
3670 } else if (_visible_track_count == 0) {
3672 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3673 if ((*i)->marked_for_display()) {
3677 h = trackviews_height() / n;
3680 /* negative value means that the visible track count has
3681 been overridden by explicit track height changes.
3683 visible_tracks_selector.set_text (X_("*"));
3687 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3688 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3691 if (str != visible_tracks_selector.get_text()) {
3692 visible_tracks_selector.set_text (str);
3697 Editor::override_visible_track_count ()
3699 _visible_track_count = -1;
3700 visible_tracks_selector.set_text ( _("*") );
3704 Editor::edit_controls_button_release (GdkEventButton* ev)
3706 if (Keyboard::is_context_menu_event (ev)) {
3707 ARDOUR_UI::instance()->add_route (current_toplevel());
3708 } else if (ev->button == 1) {
3709 selection->clear_tracks ();
3716 Editor::mouse_select_button_release (GdkEventButton* ev)
3718 /* this handles just right-clicks */
3720 if (ev->button != 3) {
3728 Editor::set_zoom_focus (ZoomFocus f)
3730 string str = zoom_focus_strings[(int)f];
3732 if (str != zoom_focus_selector.get_text()) {
3733 zoom_focus_selector.set_text (str);
3736 if (zoom_focus != f) {
3743 Editor::cycle_zoom_focus ()
3745 switch (zoom_focus) {
3747 set_zoom_focus (ZoomFocusRight);
3749 case ZoomFocusRight:
3750 set_zoom_focus (ZoomFocusCenter);
3752 case ZoomFocusCenter:
3753 set_zoom_focus (ZoomFocusPlayhead);
3755 case ZoomFocusPlayhead:
3756 set_zoom_focus (ZoomFocusMouse);
3758 case ZoomFocusMouse:
3759 set_zoom_focus (ZoomFocusEdit);
3762 set_zoom_focus (ZoomFocusLeft);
3768 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3770 /* recover or initialize pane positions. do this here rather than earlier because
3771 we don't want the positions to change the child allocations, which they seem to do.
3777 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3786 XMLNode* geometry = find_named_node (*node, "geometry");
3788 if (which == static_cast<Paned*> (&edit_pane)) {
3790 if (done & Horizontal) {
3794 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3795 _notebook_shrunk = string_is_affirmative (prop->value ());
3798 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3799 /* initial allocation is 90% to canvas, 10% to notebook */
3800 pos = (int) floor (alloc.get_width() * 0.90f);
3801 snprintf (buf, sizeof(buf), "%d", pos);
3803 pos = atoi (prop->value());
3806 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3807 edit_pane.set_position (pos);
3810 done = (Pane) (done | Horizontal);
3812 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3814 if (done & Vertical) {
3818 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3819 /* initial allocation is 90% to canvas, 10% to summary */
3820 pos = (int) floor (alloc.get_height() * 0.90f);
3821 snprintf (buf, sizeof(buf), "%d", pos);
3824 pos = atoi (prop->value());
3827 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3828 editor_summary_pane.set_position (pos);
3831 done = (Pane) (done | Vertical);
3836 Editor::set_show_measures (bool yn)
3838 if (_show_measures != yn) {
3841 if ((_show_measures = yn) == true) {
3843 tempo_lines->show();
3846 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3847 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3849 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3850 draw_measures (begin, end);
3858 Editor::toggle_follow_playhead ()
3860 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3862 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3863 set_follow_playhead (tact->get_active());
3867 /** @param yn true to follow playhead, otherwise false.
3868 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3871 Editor::set_follow_playhead (bool yn, bool catch_up)
3873 if (_follow_playhead != yn) {
3874 if ((_follow_playhead = yn) == true && catch_up) {
3876 reset_x_origin_to_follow_playhead ();
3883 Editor::toggle_stationary_playhead ()
3885 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3887 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3888 set_stationary_playhead (tact->get_active());
3893 Editor::set_stationary_playhead (bool yn)
3895 if (_stationary_playhead != yn) {
3896 if ((_stationary_playhead = yn) == true) {
3898 // FIXME need a 3.0 equivalent of this 2.X call
3899 // update_current_screen ();
3906 Editor::playlist_selector () const
3908 return *_playlist_selector;
3912 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
3914 if (paste_count == 0) {
3915 /* don't bother calculating an offset that will be zero anyway */
3919 /* calculate basic unsnapped multi-paste offset */
3920 framecnt_t offset = paste_count * duration;
3922 /* snap offset so pos + offset is aligned to the grid */
3923 framepos_t offset_pos = pos + offset;
3924 snap_to(offset_pos, RoundUpMaybe);
3925 offset = offset_pos - pos;
3931 Editor::get_grid_beat_divisions(framepos_t position)
3933 switch (_snap_type) {
3934 case SnapToBeatDiv128: return 128;
3935 case SnapToBeatDiv64: return 64;
3936 case SnapToBeatDiv32: return 32;
3937 case SnapToBeatDiv28: return 28;
3938 case SnapToBeatDiv24: return 24;
3939 case SnapToBeatDiv20: return 20;
3940 case SnapToBeatDiv16: return 16;
3941 case SnapToBeatDiv14: return 14;
3942 case SnapToBeatDiv12: return 12;
3943 case SnapToBeatDiv10: return 10;
3944 case SnapToBeatDiv8: return 8;
3945 case SnapToBeatDiv7: return 7;
3946 case SnapToBeatDiv6: return 6;
3947 case SnapToBeatDiv5: return 5;
3948 case SnapToBeatDiv4: return 4;
3949 case SnapToBeatDiv3: return 3;
3950 case SnapToBeatDiv2: return 2;
3957 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3961 const unsigned divisions = get_grid_beat_divisions(position);
3963 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
3966 switch (_snap_type) {
3968 return Evoral::Beats(1.0);
3971 return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
3979 return Evoral::Beats();
3983 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3987 ret = nudge_clock->current_duration (pos);
3988 next = ret + 1; /* XXXX fix me */
3994 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3996 ArdourDialog dialog (_("Playlist Deletion"));
3997 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3998 "If it is kept, its audio files will not be cleaned.\n"
3999 "If it is deleted, audio files used by it alone will be cleaned."),
4002 dialog.set_position (WIN_POS_CENTER);
4003 dialog.get_vbox()->pack_start (label);
4007 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4008 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4009 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4010 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4011 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4013 // by default gtk uses the left most button
4014 keep->grab_focus ();
4016 switch (dialog.run ()) {
4018 /* keep this and all remaining ones */
4023 /* delete this and all others */
4027 case RESPONSE_ACCEPT:
4028 /* delete the playlist */
4032 case RESPONSE_REJECT:
4033 /* keep the playlist */
4045 Editor::audio_region_selection_covers (framepos_t where)
4047 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4048 if ((*a)->region()->covers (where)) {
4057 Editor::prepare_for_cleanup ()
4059 cut_buffer->clear_regions ();
4060 cut_buffer->clear_playlists ();
4062 selection->clear_regions ();
4063 selection->clear_playlists ();
4065 _regions->suspend_redisplay ();
4069 Editor::finish_cleanup ()
4071 _regions->resume_redisplay ();
4075 Editor::transport_loop_location()
4078 return _session->locations()->auto_loop_location();
4085 Editor::transport_punch_location()
4088 return _session->locations()->auto_punch_location();
4095 Editor::control_layout_scroll (GdkEventScroll* ev)
4097 /* Just forward to the normal canvas scroll method. The coordinate
4098 systems are different but since the canvas is always larger than the
4099 track headers, and aligned with the trackview area, this will work.
4101 In the not too distant future this layout is going away anyway and
4102 headers will be on the canvas.
4104 return canvas_scroll_event (ev, false);
4108 Editor::session_state_saved (string)
4111 _snapshots->redisplay ();
4115 Editor::maximise_editing_space ()
4121 Gtk::Window* toplevel = current_toplevel();
4124 toplevel->fullscreen ();
4130 Editor::restore_editing_space ()
4136 Gtk::Window* toplevel = current_toplevel();
4139 toplevel->unfullscreen();
4145 * Make new playlists for a given track and also any others that belong
4146 * to the same active route group with the `select' property.
4151 Editor::new_playlists (TimeAxisView* v)
4153 begin_reversible_command (_("new playlists"));
4154 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4155 _session->playlists->get (playlists);
4156 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4157 commit_reversible_command ();
4161 * Use a copy of the current playlist for a given track and also any others that belong
4162 * to the same active route group with the `select' property.
4167 Editor::copy_playlists (TimeAxisView* v)
4169 begin_reversible_command (_("copy playlists"));
4170 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4171 _session->playlists->get (playlists);
4172 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4173 commit_reversible_command ();
4176 /** Clear the current playlist for a given track and also any others that belong
4177 * to the same active route group with the `select' property.
4182 Editor::clear_playlists (TimeAxisView* v)
4184 begin_reversible_command (_("clear playlists"));
4185 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4186 _session->playlists->get (playlists);
4187 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4188 commit_reversible_command ();
4192 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4194 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4198 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4200 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4204 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4206 atv.clear_playlist ();
4210 Editor::get_y_origin () const
4212 return vertical_adjustment.get_value ();
4215 /** Queue up a change to the viewport x origin.
4216 * @param frame New x origin.
4219 Editor::reset_x_origin (framepos_t frame)
4221 pending_visual_change.add (VisualChange::TimeOrigin);
4222 pending_visual_change.time_origin = frame;
4223 ensure_visual_change_idle_handler ();
4227 Editor::reset_y_origin (double y)
4229 pending_visual_change.add (VisualChange::YOrigin);
4230 pending_visual_change.y_origin = y;
4231 ensure_visual_change_idle_handler ();
4235 Editor::reset_zoom (framecnt_t spp)
4237 if (spp == samples_per_pixel) {
4241 pending_visual_change.add (VisualChange::ZoomLevel);
4242 pending_visual_change.samples_per_pixel = spp;
4243 ensure_visual_change_idle_handler ();
4247 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4249 reset_x_origin (frame);
4252 if (!no_save_visual) {
4253 undo_visual_stack.push_back (current_visual_state(false));
4257 Editor::VisualState::VisualState (bool with_tracks)
4258 : gui_state (with_tracks ? new GUIObjectState : 0)
4262 Editor::VisualState::~VisualState ()
4267 Editor::VisualState*
4268 Editor::current_visual_state (bool with_tracks)
4270 VisualState* vs = new VisualState (with_tracks);
4271 vs->y_position = vertical_adjustment.get_value();
4272 vs->samples_per_pixel = samples_per_pixel;
4273 vs->leftmost_frame = leftmost_frame;
4274 vs->zoom_focus = zoom_focus;
4277 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4284 Editor::undo_visual_state ()
4286 if (undo_visual_stack.empty()) {
4290 VisualState* vs = undo_visual_stack.back();
4291 undo_visual_stack.pop_back();
4294 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4297 use_visual_state (*vs);
4302 Editor::redo_visual_state ()
4304 if (redo_visual_stack.empty()) {
4308 VisualState* vs = redo_visual_stack.back();
4309 redo_visual_stack.pop_back();
4311 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4312 // why do we check here?
4313 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4316 use_visual_state (*vs);
4321 Editor::swap_visual_state ()
4323 if (undo_visual_stack.empty()) {
4324 redo_visual_state ();
4326 undo_visual_state ();
4331 Editor::use_visual_state (VisualState& vs)
4333 PBD::Unwinder<bool> nsv (no_save_visual, true);
4334 DisplaySuspender ds;
4336 vertical_adjustment.set_value (vs.y_position);
4338 set_zoom_focus (vs.zoom_focus);
4339 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4342 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4344 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4345 (*i)->clear_property_cache();
4346 (*i)->reset_visual_state ();
4350 _routes->update_visibility ();
4353 /** This is the core function that controls the zoom level of the canvas. It is called
4354 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4355 * @param spp new number of samples per pixel
4358 Editor::set_samples_per_pixel (framecnt_t spp)
4364 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4365 const framecnt_t lots_of_pixels = 4000;
4367 /* if the zoom level is greater than what you'd get trying to display 3
4368 * days of audio on a really big screen, then it's too big.
4371 if (spp * lots_of_pixels > three_days) {
4375 samples_per_pixel = spp;
4378 tempo_lines->tempo_map_changed();
4381 bool const showing_time_selection = selection->time.length() > 0;
4383 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4384 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4385 (*i)->reshow_selection (selection->time);
4389 ZoomChanged (); /* EMIT_SIGNAL */
4391 ArdourCanvas::GtkCanvasViewport* c;
4393 c = get_track_canvas();
4395 c->canvas()->zoomed ();
4398 if (playhead_cursor) {
4399 playhead_cursor->set_position (playhead_cursor->current_frame ());
4402 refresh_location_display();
4403 _summary->set_overlays_dirty ();
4405 update_marker_labels ();
4411 Editor::queue_visual_videotimeline_update ()
4414 * pending_visual_change.add (VisualChange::VideoTimeline);
4415 * or maybe even more specific: which videotimeline-image
4416 * currently it calls update_video_timeline() to update
4417 * _all outdated_ images on the video-timeline.
4418 * see 'exposeimg()' in video_image_frame.cc
4420 ensure_visual_change_idle_handler ();
4424 Editor::ensure_visual_change_idle_handler ()
4426 if (pending_visual_change.idle_handler_id < 0) {
4427 // see comment in add_to_idle_resize above.
4428 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4429 pending_visual_change.being_handled = false;
4434 Editor::_idle_visual_changer (void* arg)
4436 return static_cast<Editor*>(arg)->idle_visual_changer ();
4440 Editor::idle_visual_changer ()
4442 /* set_horizontal_position() below (and maybe other calls) call
4443 gtk_main_iteration(), so it's possible that a signal will be handled
4444 half-way through this method. If this signal wants an
4445 idle_visual_changer we must schedule another one after this one, so
4446 mark the idle_handler_id as -1 here to allow that. Also make a note
4447 that we are doing the visual change, so that changes in response to
4448 super-rapid-screen-update can be dropped if we are still processing
4452 pending_visual_change.idle_handler_id = -1;
4453 pending_visual_change.being_handled = true;
4455 VisualChange vc = pending_visual_change;
4457 pending_visual_change.pending = (VisualChange::Type) 0;
4459 visual_changer (vc);
4461 pending_visual_change.being_handled = false;
4463 return 0; /* this is always a one-shot call */
4467 Editor::visual_changer (const VisualChange& vc)
4469 double const last_time_origin = horizontal_position ();
4471 if (vc.pending & VisualChange::ZoomLevel) {
4472 set_samples_per_pixel (vc.samples_per_pixel);
4474 compute_fixed_ruler_scale ();
4476 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4477 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4479 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4480 current_bbt_points_begin, current_bbt_points_end);
4481 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4482 current_bbt_points_begin, current_bbt_points_end);
4483 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4485 update_video_timeline();
4488 if (vc.pending & VisualChange::TimeOrigin) {
4489 set_horizontal_position (vc.time_origin / samples_per_pixel);
4492 if (vc.pending & VisualChange::YOrigin) {
4493 vertical_adjustment.set_value (vc.y_origin);
4496 if (last_time_origin == horizontal_position ()) {
4497 /* changed signal not emitted */
4498 update_fixed_rulers ();
4499 redisplay_tempo (true);
4502 if (!(vc.pending & VisualChange::ZoomLevel)) {
4503 update_video_timeline();
4506 _summary->set_overlays_dirty ();
4509 struct EditorOrderTimeAxisSorter {
4510 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4511 return a->order () < b->order ();
4516 Editor::sort_track_selection (TrackViewList& sel)
4518 EditorOrderTimeAxisSorter cmp;
4523 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4526 framepos_t where = 0;
4527 EditPoint ep = _edit_point;
4529 if (Profile->get_mixbus())
4530 if (ep == EditAtSelectedMarker)
4531 ep = EditAtPlayhead;
4533 if (from_outside_canvas && (ep == EditAtMouse)) {
4534 ep = EditAtPlayhead;
4535 } else if (from_context_menu && (ep == EditAtMouse)) {
4536 return canvas_event_sample (&context_click_event, 0, 0);
4539 if (entered_marker) {
4540 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4541 return entered_marker->position();
4544 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4545 ep = EditAtSelectedMarker;
4548 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4549 ep = EditAtPlayhead;
4553 case EditAtPlayhead:
4554 if (_dragging_playhead) {
4555 where = *_control_scroll_target;
4557 where = _session->audible_frame();
4559 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4562 case EditAtSelectedMarker:
4563 if (!selection->markers.empty()) {
4565 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4568 where = loc->start();
4572 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4580 if (!mouse_frame (where, ignored)) {
4581 /* XXX not right but what can we do ? */
4585 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4593 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4595 if (!_session) return;
4597 begin_reversible_command (cmd);
4601 if ((tll = transport_loop_location()) == 0) {
4602 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4603 XMLNode &before = _session->locations()->get_state();
4604 _session->locations()->add (loc, true);
4605 _session->set_auto_loop_location (loc);
4606 XMLNode &after = _session->locations()->get_state();
4607 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4609 XMLNode &before = tll->get_state();
4610 tll->set_hidden (false, this);
4611 tll->set (start, end);
4612 XMLNode &after = tll->get_state();
4613 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4616 commit_reversible_command ();
4620 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4622 if (!_session) return;
4624 begin_reversible_command (cmd);
4628 if ((tpl = transport_punch_location()) == 0) {
4629 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4630 XMLNode &before = _session->locations()->get_state();
4631 _session->locations()->add (loc, true);
4632 _session->set_auto_punch_location (loc);
4633 XMLNode &after = _session->locations()->get_state();
4634 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4636 XMLNode &before = tpl->get_state();
4637 tpl->set_hidden (false, this);
4638 tpl->set (start, end);
4639 XMLNode &after = tpl->get_state();
4640 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4643 commit_reversible_command ();
4646 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4647 * @param rs List to which found regions are added.
4648 * @param where Time to look at.
4649 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4652 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4654 const TrackViewList* tracks;
4657 tracks = &track_views;
4662 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4664 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4667 boost::shared_ptr<Track> tr;
4668 boost::shared_ptr<Playlist> pl;
4670 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4672 boost::shared_ptr<RegionList> regions = pl->regions_at (
4673 (framepos_t) floor ( (double) where * tr->speed()));
4675 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4676 RegionView* rv = rtv->view()->find_view (*i);
4687 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4689 const TrackViewList* tracks;
4692 tracks = &track_views;
4697 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4698 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4700 boost::shared_ptr<Track> tr;
4701 boost::shared_ptr<Playlist> pl;
4703 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4705 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4706 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4708 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4710 RegionView* rv = rtv->view()->find_view (*i);
4721 /** Get regions using the following method:
4723 * Make a region list using:
4724 * (a) any selected regions
4725 * (b) the intersection of any selected tracks and the edit point(*)
4726 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4728 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4730 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4734 Editor::get_regions_from_selection_and_edit_point ()
4736 RegionSelection regions;
4738 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4739 regions.add (entered_regionview);
4741 regions = selection->regions;
4744 if ( regions.empty() ) {
4745 TrackViewList tracks = selection->tracks;
4747 if (!tracks.empty()) {
4748 /* no region selected or entered, but some selected tracks:
4749 * act on all regions on the selected tracks at the edit point
4751 framepos_t const where = get_preferred_edit_position ();
4752 get_regions_at(regions, where, tracks);
4759 /** Get regions using the following method:
4761 * Make a region list using:
4762 * (a) any selected regions
4763 * (b) the intersection of any selected tracks and the edit point(*)
4764 * (c) if neither exists, then whatever region is under the mouse
4766 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4768 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4771 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4773 RegionSelection regions;
4775 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4776 regions.add (entered_regionview);
4778 regions = selection->regions;
4781 if ( regions.empty() ) {
4782 TrackViewList tracks = selection->tracks;
4784 if (!tracks.empty()) {
4785 /* no region selected or entered, but some selected tracks:
4786 * act on all regions on the selected tracks at the edit point
4788 get_regions_at(regions, pos, tracks);
4795 /** Start with regions that are selected, or the entered regionview if none are selected.
4796 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4797 * of the regions that we started with.
4801 Editor::get_regions_from_selection_and_entered ()
4803 RegionSelection regions = selection->regions;
4805 if (regions.empty() && entered_regionview) {
4806 regions.add (entered_regionview);
4813 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4815 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4816 RouteTimeAxisView* rtav;
4818 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4819 boost::shared_ptr<Playlist> pl;
4820 std::vector<boost::shared_ptr<Region> > results;
4821 boost::shared_ptr<Track> tr;
4823 if ((tr = rtav->track()) == 0) {
4828 if ((pl = (tr->playlist())) != 0) {
4829 boost::shared_ptr<Region> r = pl->region_by_id (id);
4831 RegionView* rv = rtav->view()->find_view (r);
4833 regions.push_back (rv);
4842 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4845 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4846 MidiTimeAxisView* mtav;
4848 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4850 mtav->get_per_region_note_selection (selection);
4857 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4859 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4861 RouteTimeAxisView* tatv;
4863 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4865 boost::shared_ptr<Playlist> pl;
4866 vector<boost::shared_ptr<Region> > results;
4868 boost::shared_ptr<Track> tr;
4870 if ((tr = tatv->track()) == 0) {
4875 if ((pl = (tr->playlist())) != 0) {
4876 if (src_comparison) {
4877 pl->get_source_equivalent_regions (region, results);
4879 pl->get_region_list_equivalent_regions (region, results);
4883 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4884 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4885 regions.push_back (marv);
4894 Editor::show_rhythm_ferret ()
4896 if (rhythm_ferret == 0) {
4897 rhythm_ferret = new RhythmFerret(*this);
4900 rhythm_ferret->set_session (_session);
4901 rhythm_ferret->show ();
4902 rhythm_ferret->present ();
4906 Editor::first_idle ()
4908 MessageDialog* dialog = 0;
4910 if (track_views.size() > 1) {
4911 Timers::TimerSuspender t;
4912 dialog = new MessageDialog (
4913 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4917 ARDOUR_UI::instance()->flush_pending ();
4920 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4924 // first idle adds route children (automation tracks), so we need to redisplay here
4925 _routes->redisplay ();
4929 if (_session->undo_depth() == 0) {
4930 undo_action->set_sensitive(false);
4932 redo_action->set_sensitive(false);
4933 begin_selection_op_history ();
4939 Editor::_idle_resize (gpointer arg)
4941 return ((Editor*)arg)->idle_resize ();
4945 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4947 if (resize_idle_id < 0) {
4948 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
4949 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
4950 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
4952 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
4953 _pending_resize_amount = 0;
4956 /* make a note of the smallest resulting height, so that we can clamp the
4957 lower limit at TimeAxisView::hSmall */
4959 int32_t min_resulting = INT32_MAX;
4961 _pending_resize_amount += h;
4962 _pending_resize_view = view;
4964 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4966 if (selection->tracks.contains (_pending_resize_view)) {
4967 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4968 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4972 if (min_resulting < 0) {
4977 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4978 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4982 /** Handle pending resizing of tracks */
4984 Editor::idle_resize ()
4986 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4988 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4989 selection->tracks.contains (_pending_resize_view)) {
4991 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4992 if (*i != _pending_resize_view) {
4993 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4998 _pending_resize_amount = 0;
4999 _group_tabs->set_dirty ();
5000 resize_idle_id = -1;
5008 ENSURE_GUI_THREAD (*this, &Editor::located);
5011 playhead_cursor->set_position (_session->audible_frame ());
5012 if (_follow_playhead && !_pending_initial_locate) {
5013 reset_x_origin_to_follow_playhead ();
5017 _pending_locate_request = false;
5018 _pending_initial_locate = false;
5022 Editor::region_view_added (RegionView * rv)
5024 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5025 if (rv->region ()->id () == (*pr)) {
5026 selection->add (rv);
5027 selection->regions.pending.erase (pr);
5032 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5034 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5035 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5036 if (rv->region()->id () == (*rnote).first) {
5037 mrv->select_notes ((*rnote).second);
5038 selection->pending_midi_note_selection.erase(rnote);
5044 _summary->set_background_dirty ();
5048 Editor::region_view_removed ()
5050 _summary->set_background_dirty ();
5054 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5056 TrackViewList::const_iterator j = track_views.begin ();
5057 while (j != track_views.end()) {
5058 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5059 if (rtv && rtv->route() == r) {
5070 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5074 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5075 TimeAxisView* tv = axis_view_from_route (*i);
5085 Editor::suspend_route_redisplay ()
5088 _routes->suspend_redisplay();
5093 Editor::resume_route_redisplay ()
5096 _routes->redisplay(); // queue redisplay
5097 _routes->resume_redisplay();
5102 Editor::add_routes (RouteList& routes)
5104 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5106 RouteTimeAxisView *rtv;
5107 list<RouteTimeAxisView*> new_views;
5108 TrackViewList new_selection;
5109 bool from_scratch = (track_views.size() == 0);
5111 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5112 boost::shared_ptr<Route> route = (*x);
5114 if (route->is_auditioner() || route->is_monitor()) {
5118 DataType dt = route->input()->default_type();
5120 if (dt == ARDOUR::DataType::AUDIO) {
5121 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5122 rtv->set_route (route);
5123 } else if (dt == ARDOUR::DataType::MIDI) {
5124 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5125 rtv->set_route (route);
5127 throw unknown_type();
5130 new_views.push_back (rtv);
5131 track_views.push_back (rtv);
5132 new_selection.push_back (rtv);
5134 rtv->effective_gain_display ();
5136 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5137 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5140 if (new_views.size() > 0) {
5141 _routes->routes_added (new_views);
5142 _summary->routes_added (new_views);
5145 if (!from_scratch) {
5146 selection->tracks.clear();
5147 selection->add (new_selection);
5148 begin_selection_op_history();
5151 if (show_editor_mixer_when_tracks_arrive) {
5152 show_editor_mixer (true);
5155 editor_list_button.set_sensitive (true);
5159 Editor::timeaxisview_deleted (TimeAxisView *tv)
5161 if (tv == entered_track) {
5165 if (_session && _session->deletion_in_progress()) {
5166 /* the situation is under control */
5170 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5172 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5174 _routes->route_removed (tv);
5176 TimeAxisView::Children c = tv->get_child_list ();
5177 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5178 if (entered_track == i->get()) {
5183 /* remove it from the list of track views */
5185 TrackViewList::iterator i;
5187 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5188 i = track_views.erase (i);
5191 /* update whatever the current mixer strip is displaying, if revelant */
5193 boost::shared_ptr<Route> route;
5196 route = rtav->route ();
5199 if (current_mixer_strip && current_mixer_strip->route() == route) {
5201 TimeAxisView* next_tv;
5203 if (track_views.empty()) {
5205 } else if (i == track_views.end()) {
5206 next_tv = track_views.front();
5213 set_selected_mixer_strip (*next_tv);
5215 /* make the editor mixer strip go away setting the
5216 * button to inactive (which also unticks the menu option)
5219 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5225 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5227 if (apply_to_selection) {
5228 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5230 TrackSelection::iterator j = i;
5233 hide_track_in_display (*i, false);
5238 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5240 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5241 // this will hide the mixer strip
5242 set_selected_mixer_strip (*tv);
5245 _routes->hide_track_in_display (*tv);
5250 Editor::sync_track_view_list_and_routes ()
5252 track_views = TrackViewList (_routes->views ());
5254 _summary->set_background_dirty();
5255 _group_tabs->set_dirty ();
5257 return false; // do not call again (until needed)
5261 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5263 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5268 /** Find a RouteTimeAxisView by the ID of its route */
5270 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5272 RouteTimeAxisView* v;
5274 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5275 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5276 if(v->route()->id() == id) {
5286 Editor::fit_route_group (RouteGroup *g)
5288 TrackViewList ts = axis_views_from_routes (g->route_list ());
5293 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5295 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5298 _session->cancel_audition ();
5302 if (_session->is_auditioning()) {
5303 _session->cancel_audition ();
5304 if (r == last_audition_region) {
5309 _session->audition_region (r);
5310 last_audition_region = r;
5315 Editor::hide_a_region (boost::shared_ptr<Region> r)
5317 r->set_hidden (true);
5321 Editor::show_a_region (boost::shared_ptr<Region> r)
5323 r->set_hidden (false);
5327 Editor::audition_region_from_region_list ()
5329 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5333 Editor::hide_region_from_region_list ()
5335 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5339 Editor::show_region_in_region_list ()
5341 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5345 Editor::step_edit_status_change (bool yn)
5348 start_step_editing ();
5350 stop_step_editing ();
5355 Editor::start_step_editing ()
5357 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5361 Editor::stop_step_editing ()
5363 step_edit_connection.disconnect ();
5367 Editor::check_step_edit ()
5369 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5370 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5372 mtv->check_step_edit ();
5376 return true; // do it again, till we stop
5380 Editor::scroll_press (Direction dir)
5382 ++_scroll_callbacks;
5384 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5385 /* delay the first auto-repeat */
5391 scroll_backward (1);
5399 scroll_up_one_track ();
5403 scroll_down_one_track ();
5407 /* do hacky auto-repeat */
5408 if (!_scroll_connection.connected ()) {
5410 _scroll_connection = Glib::signal_timeout().connect (
5411 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5414 _scroll_callbacks = 0;
5421 Editor::scroll_release ()
5423 _scroll_connection.disconnect ();
5426 /** Queue a change for the Editor viewport x origin to follow the playhead */
5428 Editor::reset_x_origin_to_follow_playhead ()
5430 framepos_t const frame = playhead_cursor->current_frame ();
5432 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5434 if (_session->transport_speed() < 0) {
5436 if (frame > (current_page_samples() / 2)) {
5437 center_screen (frame-(current_page_samples()/2));
5439 center_screen (current_page_samples()/2);
5446 if (frame < leftmost_frame) {
5448 if (_session->transport_rolling()) {
5449 /* rolling; end up with the playhead at the right of the page */
5450 l = frame - current_page_samples ();
5452 /* not rolling: end up with the playhead 1/4 of the way along the page */
5453 l = frame - current_page_samples() / 4;
5457 if (_session->transport_rolling()) {
5458 /* rolling: end up with the playhead on the left of the page */
5461 /* not rolling: end up with the playhead 3/4 of the way along the page */
5462 l = frame - 3 * current_page_samples() / 4;
5470 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5476 Editor::super_rapid_screen_update ()
5478 if (!_session || !_session->engine().running()) {
5482 /* METERING / MIXER STRIPS */
5484 /* update track meters, if required */
5485 if (contents().is_mapped() && meters_running) {
5486 RouteTimeAxisView* rtv;
5487 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5488 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5489 rtv->fast_update ();
5494 /* and any current mixer strip */
5495 if (current_mixer_strip) {
5496 current_mixer_strip->fast_update ();
5499 /* PLAYHEAD AND VIEWPORT */
5501 framepos_t const frame = _session->audible_frame();
5503 /* There are a few reasons why we might not update the playhead / viewport stuff:
5505 * 1. we don't update things when there's a pending locate request, otherwise
5506 * when the editor requests a locate there is a chance that this method
5507 * will move the playhead before the locate request is processed, causing
5509 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5510 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5513 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5515 last_update_frame = frame;
5517 if (!_dragging_playhead) {
5518 playhead_cursor->set_position (frame);
5521 if (!_stationary_playhead) {
5523 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5524 /* We only do this if we aren't already
5525 handling a visual change (ie if
5526 pending_visual_change.being_handled is
5527 false) so that these requests don't stack
5528 up there are too many of them to handle in
5531 reset_x_origin_to_follow_playhead ();
5536 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5537 framepos_t const frame = playhead_cursor->current_frame ();
5538 double target = ((double)frame - (double)current_page_samples()/2.0);
5539 if (target <= 0.0) {
5542 // compare to EditorCursor::set_position()
5543 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5544 double const new_pos = sample_to_pixel_unrounded (target);
5545 if (rint (new_pos) != rint (old_pos)) {
5546 reset_x_origin (pixel_to_sample (floor (new_pos)));
5557 Editor::session_going_away ()
5559 _have_idled = false;
5561 _session_connections.drop_connections ();
5563 super_rapid_screen_update_connection.disconnect ();
5565 selection->clear ();
5566 cut_buffer->clear ();
5568 clicked_regionview = 0;
5569 clicked_axisview = 0;
5570 clicked_routeview = 0;
5571 entered_regionview = 0;
5573 last_update_frame = 0;
5576 playhead_cursor->hide ();
5578 /* rip everything out of the list displays */
5582 _route_groups->clear ();
5584 /* do this first so that deleting a track doesn't reset cms to null
5585 and thus cause a leak.
5588 if (current_mixer_strip) {
5589 if (current_mixer_strip->get_parent() != 0) {
5590 global_hpacker.remove (*current_mixer_strip);
5592 delete current_mixer_strip;
5593 current_mixer_strip = 0;
5596 /* delete all trackviews */
5598 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5601 track_views.clear ();
5603 nudge_clock->set_session (0);
5605 editor_list_button.set_active(false);
5606 editor_list_button.set_sensitive(false);
5608 /* clear tempo/meter rulers */
5609 remove_metric_marks ();
5611 clear_marker_display ();
5613 stop_step_editing ();
5617 /* get rid of any existing editor mixer strip */
5619 WindowTitle title(Glib::get_application_name());
5620 title += _("Editor");
5622 own_window()->set_title (title.get_string());
5625 SessionHandlePtr::session_going_away ();
5629 Editor::manage_action_scripts ()
5631 ARDOUR_UI::instance()->lua_script_manager();
5635 Editor::trigger_script (int i)
5637 LuaInstance::instance()-> call_action (i);
5641 Editor::set_script_action_name (int i, const std::string& n)
5643 string const a = string_compose (X_("script-action-%1"), i + 1);
5644 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5647 act->set_label (string_compose (_("Unset #%1"), i + 1));
5654 Editor::show_editor_list (bool yn)
5657 _the_notebook.show ();
5659 _the_notebook.hide ();
5664 Editor::change_region_layering_order (bool from_context_menu)
5666 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5668 if (!clicked_routeview) {
5669 if (layering_order_editor) {
5670 layering_order_editor->hide ();
5675 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5681 boost::shared_ptr<Playlist> pl = track->playlist();
5687 if (layering_order_editor == 0) {
5688 layering_order_editor = new RegionLayeringOrderEditor (*this);
5691 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5692 layering_order_editor->maybe_present ();
5696 Editor::update_region_layering_order_editor ()
5698 if (layering_order_editor && layering_order_editor->is_visible ()) {
5699 change_region_layering_order (true);
5704 Editor::setup_fade_images ()
5706 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5707 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5708 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5709 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5710 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5712 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5713 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5714 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5715 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5716 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5718 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5719 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5720 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5721 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5722 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5724 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5725 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5726 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5727 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5728 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5732 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5734 Editor::action_menu_item (std::string const & name)
5736 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5739 return *manage (a->create_menu_item ());
5743 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5745 EventBox* b = manage (new EventBox);
5746 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5747 Label* l = manage (new Label (name));
5751 _the_notebook.append_page (widget, *b);
5755 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5757 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5758 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5761 if (ev->type == GDK_2BUTTON_PRESS) {
5763 /* double-click on a notebook tab shrinks or expands the notebook */
5765 if (_notebook_shrunk) {
5766 if (pre_notebook_shrink_pane_width) {
5767 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5769 _notebook_shrunk = false;
5771 pre_notebook_shrink_pane_width = edit_pane.get_position();
5773 /* this expands the LHS of the edit pane to cover the notebook
5774 PAGE but leaves the tabs visible.
5776 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5777 _notebook_shrunk = true;
5785 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5787 using namespace Menu_Helpers;
5789 MenuList& items = _control_point_context_menu.items ();
5792 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5793 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5794 if (!can_remove_control_point (item)) {
5795 items.back().set_sensitive (false);
5798 _control_point_context_menu.popup (event->button.button, event->button.time);
5802 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5804 using namespace Menu_Helpers;
5806 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5811 /* We need to get the selection here and pass it to the operations, since
5812 popping up the menu will cause a region leave event which clears
5813 entered_regionview. */
5815 MidiRegionView& mrv = note->region_view();
5816 const RegionSelection rs = get_regions_from_selection_and_entered ();
5817 const uint32_t sel_size = mrv.selection_size ();
5819 MenuList& items = _note_context_menu.items();
5823 items.push_back(MenuElem(_("Delete"),
5824 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5827 items.push_back(MenuElem(_("Edit..."),
5828 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5829 if (sel_size != 1) {
5830 items.back().set_sensitive (false);
5833 items.push_back(MenuElem(_("Transpose..."),
5834 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
5837 items.push_back(MenuElem(_("Legatize"),
5838 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5840 items.back().set_sensitive (false);
5843 items.push_back(MenuElem(_("Quantize..."),
5844 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5846 items.push_back(MenuElem(_("Remove Overlap"),
5847 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5849 items.back().set_sensitive (false);
5852 items.push_back(MenuElem(_("Transform..."),
5853 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5855 _note_context_menu.popup (event->button.button, event->button.time);
5859 Editor::zoom_vertical_modifier_released()
5861 _stepping_axis_view = 0;
5865 Editor::ui_parameter_changed (string parameter)
5867 if (parameter == "icon-set") {
5868 while (!_cursor_stack.empty()) {
5869 _cursor_stack.pop_back();
5871 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
5872 _cursor_stack.push_back(_cursors->grabber);
5873 } else if (parameter == "draggable-playhead") {
5874 if (_verbose_cursor) {
5875 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
5881 Editor::use_own_window (bool and_fill_it)
5883 bool new_window = !own_window();
5885 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
5887 if (win && new_window) {
5888 win->set_name ("EditorWindow");
5890 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
5892 // win->signal_realize().connect (*this, &Editor::on_realize);
5893 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
5894 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
5895 win->set_data ("ardour-bindings", bindings);
5900 DisplaySuspender ds;
5901 contents().show_all ();
5903 /* XXX: this is a bit unfortunate; it would probably
5904 be nicer if we could just call show () above rather
5905 than needing the show_all ()
5908 /* re-hide stuff if necessary */
5909 editor_list_button_toggled ();
5910 parameter_changed ("show-summary");
5911 parameter_changed ("show-group-tabs");
5912 parameter_changed ("show-zoom-tools");
5914 /* now reset all audio_time_axis heights, because widgets might need
5920 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5921 tv = (static_cast<TimeAxisView*>(*i));
5922 tv->reset_height ();
5925 if (current_mixer_strip) {
5926 current_mixer_strip->hide_things ();
5927 current_mixer_strip->parameter_changed ("mixer-element-visibility");