2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include "gtkmm2ext/utils.h"
63 #include "gtkmm2ext/window_title.h"
64 #include "gtkmm2ext/choice.h"
65 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
67 #include "ardour/audio_track.h"
68 #include "ardour/audioengine.h"
69 #include "ardour/audioregion.h"
70 #include "ardour/lmath.h"
71 #include "ardour/location.h"
72 #include "ardour/profile.h"
73 #include "ardour/route_group.h"
74 #include "ardour/session_playlists.h"
75 #include "ardour/tempo.h"
76 #include "ardour/utils.h"
78 #include "canvas/debug.h"
79 #include "canvas/text.h"
81 #include "control_protocol/control_protocol.h"
84 #include "analysis_window.h"
85 #include "audio_clock.h"
86 #include "audio_region_view.h"
87 #include "audio_streamview.h"
88 #include "audio_time_axis.h"
89 #include "automation_time_axis.h"
90 #include "bundle_manager.h"
91 #include "crossfade_edit.h"
95 #include "editor_cursors.h"
96 #include "editor_drag.h"
97 #include "editor_group_tabs.h"
98 #include "editor_locations.h"
99 #include "editor_regions.h"
100 #include "editor_route_groups.h"
101 #include "editor_routes.h"
102 #include "editor_snapshots.h"
103 #include "editor_summary.h"
104 #include "global_port_matrix.h"
105 #include "gui_object.h"
106 #include "gui_thread.h"
107 #include "keyboard.h"
109 #include "midi_region_view.h"
110 #include "midi_time_axis.h"
111 #include "mixer_strip.h"
112 #include "mixer_ui.h"
113 #include "mouse_cursors.h"
114 #include "note_base.h"
115 #include "playlist_selector.h"
116 #include "public_editor.h"
117 #include "quantize_dialog.h"
118 #include "region_layering_order_editor.h"
119 #include "rgb_macros.h"
120 #include "rhythm_ferret.h"
121 #include "selection.h"
123 #include "tempo_lines.h"
124 #include "time_axis_view.h"
126 #include "tooltips.h"
127 #include "ui_config.h"
129 #include "verbose_cursor.h"
134 using namespace ARDOUR;
135 using namespace ARDOUR_UI_UTILS;
138 using namespace Glib;
139 using namespace Gtkmm2ext;
140 using namespace Editing;
142 using PBD::internationalize;
144 using Gtkmm2ext::Keyboard;
146 double Editor::timebar_height = 15.0;
148 static const gchar *_snap_type_strings[] = {
182 static const gchar *_snap_mode_strings[] = {
189 static const gchar *_edit_point_strings[] = {
196 static const gchar *_edit_mode_strings[] = {
204 static const gchar *_zoom_focus_strings[] = {
214 #ifdef USE_RUBBERBAND
215 static const gchar *_rb_opt_strings[] = {
218 N_("Balanced multitimbral mixture"),
219 N_("Unpitched percussion with stable notes"),
220 N_("Crisp monophonic instrumental"),
221 N_("Unpitched solo percussion"),
222 N_("Resample without preserving pitch"),
227 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
230 pane_size_watcher (Paned* pane)
232 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
236 Quartz: impossible to access
238 so stop that by preventing it from ever getting too narrow. 35
239 pixels is basically a rough guess at the tab width.
244 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
246 gint pos = pane->get_position ();
248 if (pos > max_width_of_lhs) {
249 pane->set_position (max_width_of_lhs);
254 : PublicEditor (global_hpacker)
255 , editor_mixer_strip_width (Wide)
256 , constructed (false)
257 , _playlist_selector (0)
258 , no_save_visual (false)
260 , samples_per_pixel (2048)
261 , zoom_focus (ZoomFocusPlayhead)
262 , mouse_mode (MouseObject)
263 , pre_internal_snap_type (SnapToBeat)
264 , pre_internal_snap_mode (SnapOff)
265 , internal_snap_type (SnapToBeat)
266 , internal_snap_mode (SnapOff)
267 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
268 , _notebook_shrunk (false)
269 , location_marker_color (0)
270 , location_range_color (0)
271 , location_loop_color (0)
272 , location_punch_color (0)
273 , location_cd_marker_color (0)
275 , _show_marker_lines (false)
276 , clicked_axisview (0)
277 , clicked_routeview (0)
278 , clicked_regionview (0)
279 , clicked_selection (0)
280 , clicked_control_point (0)
281 , button_release_can_deselect (true)
282 , _mouse_changed_selection (false)
283 , region_edit_menu_split_item (0)
284 , region_edit_menu_split_multichannel_item (0)
285 , track_region_edit_playlist_menu (0)
286 , track_edit_playlist_submenu (0)
287 , track_selection_edit_playlist_submenu (0)
288 , _popup_region_menu_item (0)
290 , _track_canvas_viewport (0)
291 , within_track_canvas (false)
292 , _verbose_cursor (0)
296 , range_marker_group (0)
297 , transport_marker_group (0)
298 , cd_marker_group (0)
299 , _time_markers_group (0)
300 , hv_scroll_group (0)
302 , cursor_scroll_group (0)
303 , no_scroll_group (0)
304 , _trackview_group (0)
305 , _drag_motion_group (0)
306 , _canvas_drop_zone (0)
307 , no_ruler_shown_update (false)
308 , ruler_grabbed_widget (0)
310 , minsec_mark_interval (0)
311 , minsec_mark_modulo (0)
313 , timecode_mark_modulo (0)
314 , timecode_nmarks (0)
315 , _samples_ruler_interval (0)
318 , bbt_bar_helper_on (0)
319 , bbt_accent_modulo (0)
324 , visible_timebars (0)
325 , editor_ruler_menu (0)
329 , range_marker_bar (0)
330 , transport_marker_bar (0)
332 , minsec_label (_("Mins:Secs"))
333 , bbt_label (_("Bars:Beats"))
334 , timecode_label (_("Timecode"))
335 , samples_label (_("Samples"))
336 , tempo_label (_("Tempo"))
337 , meter_label (_("Meter"))
338 , mark_label (_("Location Markers"))
339 , range_mark_label (_("Range Markers"))
340 , transport_mark_label (_("Loop/Punch Ranges"))
341 , cd_mark_label (_("CD Markers"))
342 , videotl_label (_("Video Timeline"))
344 , playhead_cursor (0)
345 , edit_packer (4, 4, true)
346 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
347 , horizontal_adjustment (0.0, 0.0, 1e16)
348 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
349 , controls_layout (unused_adjustment, vertical_adjustment)
350 , _scroll_callbacks (0)
351 , _visible_canvas_width (0)
352 , _visible_canvas_height (0)
353 , _full_canvas_height (0)
354 , edit_controls_left_menu (0)
355 , edit_controls_right_menu (0)
356 , last_update_frame (0)
357 , cut_buffer_start (0)
358 , cut_buffer_length (0)
359 , button_bindings (0)
363 , current_interthread_info (0)
364 , analysis_window (0)
365 , select_new_marker (false)
367 , scrubbing_direction (0)
368 , scrub_reversals (0)
369 , scrub_reverse_distance (0)
370 , have_pending_keyboard_selection (false)
371 , pending_keyboard_selection_start (0)
372 , _snap_type (SnapToBeat)
373 , _snap_mode (SnapOff)
374 , snap_threshold (5.0)
375 , ignore_gui_changes (false)
376 , _drags (new DragManager (this))
378 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
379 , _dragging_playhead (false)
380 , _dragging_edit_point (false)
381 , _show_measures (true)
382 , _follow_playhead (true)
383 , _stationary_playhead (false)
386 , global_rect_group (0)
387 , time_line_group (0)
388 , tempo_or_meter_marker_menu (0)
390 , range_marker_menu (0)
391 , transport_marker_menu (0)
392 , new_transport_marker_menu (0)
394 , marker_menu_item (0)
395 , bbt_beat_subdivision (4)
396 , _visible_track_count (-1)
397 , toolbar_selection_clock_table (2,3)
398 , automation_mode_button (_("mode"))
399 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
400 , selection (new Selection (this))
401 , cut_buffer (new Selection (this))
402 , _selection_memento (new SelectionMemento())
403 , _all_region_actions_sensitized (false)
404 , _ignore_region_action (false)
405 , _last_region_menu_was_main (false)
406 , _ignore_follow_edits (false)
407 , cd_marker_bar_drag_rect (0)
408 , range_bar_drag_rect (0)
409 , transport_bar_drag_rect (0)
410 , transport_bar_range_rect (0)
411 , transport_bar_preroll_rect (0)
412 , transport_bar_postroll_rect (0)
413 , transport_loop_range_rect (0)
414 , transport_punch_range_rect (0)
415 , transport_punchin_line (0)
416 , transport_punchout_line (0)
417 , transport_preroll_rect (0)
418 , transport_postroll_rect (0)
420 , rubberband_rect (0)
426 , autoscroll_horizontal_allowed (false)
427 , autoscroll_vertical_allowed (false)
429 , autoscroll_widget (0)
430 , show_gain_after_trim (false)
431 , selection_op_cmd_depth (0)
432 , selection_op_history_it (0)
434 , current_mixer_strip (0)
435 , show_editor_mixer_when_tracks_arrive (false)
436 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
437 , current_stepping_trackview (0)
438 , last_track_height_step_timestamp (0)
440 , entered_regionview (0)
441 , clear_entered_track (false)
442 , _edit_point (EditAtMouse)
443 , meters_running (false)
445 , _have_idled (false)
446 , resize_idle_id (-1)
447 , _pending_resize_amount (0)
448 , _pending_resize_view (0)
449 , _pending_locate_request (false)
450 , _pending_initial_locate (false)
454 , layering_order_editor (0)
455 , _last_cut_copy_source_track (0)
456 , _region_selection_change_updates_region_list (true)
458 , _following_mixer_selection (false)
459 , _control_point_toggled_on_press (false)
460 , _stepping_axis_view (0)
461 , quantize_dialog (0)
462 , _main_menu_disabler (0)
463 , myactions (X_("editor"))
465 /* we are a singleton */
467 PublicEditor::_instance = this;
471 last_event_time.tv_sec = 0;
472 last_event_time.tv_usec = 0;
474 selection_op_history.clear();
477 snap_type_strings = I18N (_snap_type_strings);
478 snap_mode_strings = I18N (_snap_mode_strings);
479 zoom_focus_strings = I18N (_zoom_focus_strings);
480 edit_mode_strings = I18N (_edit_mode_strings);
481 edit_point_strings = I18N (_edit_point_strings);
482 #ifdef USE_RUBBERBAND
483 rb_opt_strings = I18N (_rb_opt_strings);
487 build_edit_mode_menu();
488 build_zoom_focus_menu();
489 build_track_count_menu();
490 build_snap_mode_menu();
491 build_snap_type_menu();
492 build_edit_point_menu();
494 location_marker_color = UIConfiguration::instance().color ("location marker");
495 location_range_color = UIConfiguration::instance().color ("location range");
496 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
497 location_loop_color = UIConfiguration::instance().color ("location loop");
498 location_punch_color = UIConfiguration::instance().color ("location punch");
500 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
502 TimeAxisView::setup_sizes ();
503 ArdourMarker::setup_sizes (timebar_height);
505 bbt_label.set_name ("EditorRulerLabel");
506 bbt_label.set_size_request (-1, (int)timebar_height);
507 bbt_label.set_alignment (1.0, 0.5);
508 bbt_label.set_padding (5,0);
510 bbt_label.set_no_show_all();
511 minsec_label.set_name ("EditorRulerLabel");
512 minsec_label.set_size_request (-1, (int)timebar_height);
513 minsec_label.set_alignment (1.0, 0.5);
514 minsec_label.set_padding (5,0);
515 minsec_label.hide ();
516 minsec_label.set_no_show_all();
517 timecode_label.set_name ("EditorRulerLabel");
518 timecode_label.set_size_request (-1, (int)timebar_height);
519 timecode_label.set_alignment (1.0, 0.5);
520 timecode_label.set_padding (5,0);
521 timecode_label.hide ();
522 timecode_label.set_no_show_all();
523 samples_label.set_name ("EditorRulerLabel");
524 samples_label.set_size_request (-1, (int)timebar_height);
525 samples_label.set_alignment (1.0, 0.5);
526 samples_label.set_padding (5,0);
527 samples_label.hide ();
528 samples_label.set_no_show_all();
530 tempo_label.set_name ("EditorRulerLabel");
531 tempo_label.set_size_request (-1, (int)timebar_height);
532 tempo_label.set_alignment (1.0, 0.5);
533 tempo_label.set_padding (5,0);
535 tempo_label.set_no_show_all();
537 meter_label.set_name ("EditorRulerLabel");
538 meter_label.set_size_request (-1, (int)timebar_height);
539 meter_label.set_alignment (1.0, 0.5);
540 meter_label.set_padding (5,0);
542 meter_label.set_no_show_all();
544 if (Profile->get_trx()) {
545 mark_label.set_text (_("Markers"));
547 mark_label.set_name ("EditorRulerLabel");
548 mark_label.set_size_request (-1, (int)timebar_height);
549 mark_label.set_alignment (1.0, 0.5);
550 mark_label.set_padding (5,0);
552 mark_label.set_no_show_all();
554 cd_mark_label.set_name ("EditorRulerLabel");
555 cd_mark_label.set_size_request (-1, (int)timebar_height);
556 cd_mark_label.set_alignment (1.0, 0.5);
557 cd_mark_label.set_padding (5,0);
558 cd_mark_label.hide();
559 cd_mark_label.set_no_show_all();
561 videotl_bar_height = 4;
562 videotl_label.set_name ("EditorRulerLabel");
563 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
564 videotl_label.set_alignment (1.0, 0.5);
565 videotl_label.set_padding (5,0);
566 videotl_label.hide();
567 videotl_label.set_no_show_all();
569 range_mark_label.set_name ("EditorRulerLabel");
570 range_mark_label.set_size_request (-1, (int)timebar_height);
571 range_mark_label.set_alignment (1.0, 0.5);
572 range_mark_label.set_padding (5,0);
573 range_mark_label.hide();
574 range_mark_label.set_no_show_all();
576 transport_mark_label.set_name ("EditorRulerLabel");
577 transport_mark_label.set_size_request (-1, (int)timebar_height);
578 transport_mark_label.set_alignment (1.0, 0.5);
579 transport_mark_label.set_padding (5,0);
580 transport_mark_label.hide();
581 transport_mark_label.set_no_show_all();
583 initialize_canvas ();
585 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
587 _summary = new EditorSummary (this);
589 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
590 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
592 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
594 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
595 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
597 edit_controls_vbox.set_spacing (0);
598 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
599 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
601 HBox* h = manage (new HBox);
602 _group_tabs = new EditorGroupTabs (this);
603 if (!ARDOUR::Profile->get_trx()) {
604 h->pack_start (*_group_tabs, PACK_SHRINK);
606 h->pack_start (edit_controls_vbox);
607 controls_layout.add (*h);
609 controls_layout.set_name ("EditControlsBase");
610 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
611 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
612 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
614 _cursors = new MouseCursors;
615 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
616 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
618 /* Push default cursor to ever-present bottom of cursor stack. */
619 push_canvas_cursor(_cursors->grabber);
621 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
623 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
624 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
625 pad_line_1->set_outline_color (0xFF0000FF);
631 edit_packer.set_col_spacings (0);
632 edit_packer.set_row_spacings (0);
633 edit_packer.set_homogeneous (false);
634 edit_packer.set_border_width (0);
635 edit_packer.set_name ("EditorWindow");
637 time_bars_event_box.add (time_bars_vbox);
638 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
639 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
641 /* labels for the time bars */
642 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
644 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
646 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
648 bottom_hbox.set_border_width (2);
649 bottom_hbox.set_spacing (3);
651 _route_groups = new EditorRouteGroups (this);
652 _routes = new EditorRoutes (this);
653 _regions = new EditorRegions (this);
654 _snapshots = new EditorSnapshots (this);
655 _locations = new EditorLocations (this);
657 /* these are static location signals */
659 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
660 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
661 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
663 add_notebook_page (_("Regions"), _regions->widget ());
664 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
665 add_notebook_page (_("Snapshots"), _snapshots->widget ());
666 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
667 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
669 _the_notebook.set_show_tabs (true);
670 _the_notebook.set_scrollable (true);
671 _the_notebook.popup_disable ();
672 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
673 _the_notebook.show_all ();
675 _notebook_shrunk = false;
677 editor_summary_pane.pack1(edit_packer);
679 Button* summary_arrows_left_left = manage (new Button);
680 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
681 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
682 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
684 Button* summary_arrows_left_right = manage (new Button);
685 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
686 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
687 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
689 VBox* summary_arrows_left = manage (new VBox);
690 summary_arrows_left->pack_start (*summary_arrows_left_left);
691 summary_arrows_left->pack_start (*summary_arrows_left_right);
693 Button* summary_arrows_right_up = manage (new Button);
694 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
695 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
696 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
698 Button* summary_arrows_right_down = manage (new Button);
699 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
700 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
701 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
703 VBox* summary_arrows_right = manage (new VBox);
704 summary_arrows_right->pack_start (*summary_arrows_right_up);
705 summary_arrows_right->pack_start (*summary_arrows_right_down);
707 Frame* summary_frame = manage (new Frame);
708 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
710 summary_frame->add (*_summary);
711 summary_frame->show ();
713 _summary_hbox.pack_start (*summary_arrows_left, false, false);
714 _summary_hbox.pack_start (*summary_frame, true, true);
715 _summary_hbox.pack_start (*summary_arrows_right, false, false);
717 if (!ARDOUR::Profile->get_trx()) {
718 editor_summary_pane.pack2 (_summary_hbox);
721 edit_pane.pack1 (editor_summary_pane, true, true);
722 if (!ARDOUR::Profile->get_trx()) {
723 edit_pane.pack2 (_the_notebook, false, true);
726 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
728 /* XXX: editor_summary_pane might need similar to the edit_pane */
730 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
732 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
733 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
735 top_hbox.pack_start (toolbar_frame);
737 HBox *hbox = manage (new HBox);
738 hbox->pack_start (edit_pane, true, true);
740 global_vpacker.pack_start (top_hbox, false, false);
741 global_vpacker.pack_start (*hbox, true, true);
742 global_hpacker.pack_start (global_vpacker, true, true);
744 /* need to show the "contents" widget so that notebook will show if tab is switched to
747 global_hpacker.show ();
749 /* register actions now so that set_state() can find them and set toggles/checks etc */
756 _playlist_selector = new PlaylistSelector();
757 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
759 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
763 nudge_forward_button.set_name ("nudge button");
764 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
766 nudge_backward_button.set_name ("nudge button");
767 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
769 fade_context_menu.set_name ("ArdourContextMenu");
771 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
773 /* allow external control surfaces/protocols to do various things */
775 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
776 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
777 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
778 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
779 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
780 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
781 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
782 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
783 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
784 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
785 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
786 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
787 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
788 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
790 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
791 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
792 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
793 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
794 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
796 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
798 /* problematic: has to return a value and thus cannot be x-thread */
800 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
802 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
803 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
805 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
807 _ignore_region_action = false;
808 _last_region_menu_was_main = false;
809 _popup_region_menu_item = 0;
811 _ignore_follow_edits = false;
813 _show_marker_lines = false;
815 /* Button bindings */
817 button_bindings = new Bindings ("editor-mouse");
819 XMLNode* node = button_settings();
821 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
822 button_bindings->load_operation (**i);
828 /* grab current parameter state */
829 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
830 UIConfiguration::instance().map_parameters (pc);
832 setup_fade_images ();
839 delete button_bindings;
841 delete _route_groups;
842 delete _track_canvas_viewport;
845 delete quantize_dialog;
851 delete _playlist_selector;
853 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
859 Editor::button_settings () const
861 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
862 XMLNode* node = find_named_node (*settings, X_("Buttons"));
865 node = new XMLNode (X_("Buttons"));
872 Editor::get_smart_mode () const
874 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
878 Editor::catch_vanishing_regionview (RegionView *rv)
880 /* note: the selection will take care of the vanishing
881 audioregionview by itself.
884 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
888 if (clicked_regionview == rv) {
889 clicked_regionview = 0;
892 if (entered_regionview == rv) {
893 set_entered_regionview (0);
896 if (!_all_region_actions_sensitized) {
897 sensitize_all_region_actions (true);
902 Editor::set_entered_regionview (RegionView* rv)
904 if (rv == entered_regionview) {
908 if (entered_regionview) {
909 entered_regionview->exited ();
912 entered_regionview = rv;
914 if (entered_regionview != 0) {
915 entered_regionview->entered ();
918 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
919 /* This RegionView entry might have changed what region actions
920 are allowed, so sensitize them all in case a key is pressed.
922 sensitize_all_region_actions (true);
927 Editor::set_entered_track (TimeAxisView* tav)
930 entered_track->exited ();
936 entered_track->entered ();
941 Editor::instant_save ()
943 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
948 _session->add_instant_xml(get_state());
950 Config->add_instant_xml(get_state());
955 Editor::control_vertical_zoom_in_all ()
957 tav_zoom_smooth (false, true);
961 Editor::control_vertical_zoom_out_all ()
963 tav_zoom_smooth (true, true);
967 Editor::control_vertical_zoom_in_selected ()
969 tav_zoom_smooth (false, false);
973 Editor::control_vertical_zoom_out_selected ()
975 tav_zoom_smooth (true, false);
979 Editor::control_view (uint32_t view)
981 goto_visual_state (view);
985 Editor::control_unselect ()
987 selection->clear_tracks ();
991 Editor::control_select (uint32_t rid, Selection::Operation op)
993 /* handles the (static) signal from the ControlProtocol class that
994 * requests setting the selected track to a given RID
1001 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1007 TimeAxisView* tav = axis_view_from_route (r);
1011 case Selection::Add:
1012 selection->add (tav);
1014 case Selection::Toggle:
1015 selection->toggle (tav);
1017 case Selection::Extend:
1019 case Selection::Set:
1020 selection->set (tav);
1024 selection->clear_tracks ();
1029 Editor::control_step_tracks_up ()
1031 scroll_tracks_up_line ();
1035 Editor::control_step_tracks_down ()
1037 scroll_tracks_down_line ();
1041 Editor::control_scroll (float fraction)
1043 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1049 double step = fraction * current_page_samples();
1052 _control_scroll_target is an optional<T>
1054 it acts like a pointer to an framepos_t, with
1055 a operator conversion to boolean to check
1056 that it has a value could possibly use
1057 playhead_cursor->current_frame to store the
1058 value and a boolean in the class to know
1059 when it's out of date
1062 if (!_control_scroll_target) {
1063 _control_scroll_target = _session->transport_frame();
1064 _dragging_playhead = true;
1067 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1068 *_control_scroll_target = 0;
1069 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1070 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1072 *_control_scroll_target += (framepos_t) trunc (step);
1075 /* move visuals, we'll catch up with it later */
1077 playhead_cursor->set_position (*_control_scroll_target);
1078 UpdateAllTransportClocks (*_control_scroll_target);
1080 if (*_control_scroll_target > (current_page_samples() / 2)) {
1081 /* try to center PH in window */
1082 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1088 Now we do a timeout to actually bring the session to the right place
1089 according to the playhead. This is to avoid reading disk buffers on every
1090 call to control_scroll, which is driven by ScrollTimeline and therefore
1091 probably by a control surface wheel which can generate lots of events.
1093 /* cancel the existing timeout */
1095 control_scroll_connection.disconnect ();
1097 /* add the next timeout */
1099 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1103 Editor::deferred_control_scroll (framepos_t /*target*/)
1105 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1106 // reset for next stream
1107 _control_scroll_target = boost::none;
1108 _dragging_playhead = false;
1113 Editor::access_action (std::string action_group, std::string action_item)
1119 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1122 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1130 Editor::on_realize ()
1134 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1135 start_lock_event_timing ();
1140 Editor::start_lock_event_timing ()
1142 /* check if we should lock the GUI every 30 seconds */
1144 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1148 Editor::generic_event_handler (GdkEvent* ev)
1151 case GDK_BUTTON_PRESS:
1152 case GDK_BUTTON_RELEASE:
1153 case GDK_MOTION_NOTIFY:
1155 case GDK_KEY_RELEASE:
1156 if (contents().is_mapped()) {
1157 gettimeofday (&last_event_time, 0);
1161 case GDK_LEAVE_NOTIFY:
1162 switch (ev->crossing.detail) {
1163 case GDK_NOTIFY_UNKNOWN:
1164 case GDK_NOTIFY_INFERIOR:
1165 case GDK_NOTIFY_ANCESTOR:
1167 case GDK_NOTIFY_VIRTUAL:
1168 case GDK_NOTIFY_NONLINEAR:
1169 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1170 /* leaving window, so reset focus, thus ending any and
1171 all text entry operations.
1186 Editor::lock_timeout_callback ()
1188 struct timeval now, delta;
1190 gettimeofday (&now, 0);
1192 timersub (&now, &last_event_time, &delta);
1194 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1196 /* don't call again. Returning false will effectively
1197 disconnect us from the timer callback.
1199 unlock() will call start_lock_event_timing() to get things
1209 Editor::map_position_change (framepos_t frame)
1211 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1213 if (_session == 0) {
1217 if (_follow_playhead) {
1218 center_screen (frame);
1221 playhead_cursor->set_position (frame);
1225 Editor::center_screen (framepos_t frame)
1227 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1229 /* if we're off the page, then scroll.
1232 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1233 center_screen_internal (frame, page);
1238 Editor::center_screen_internal (framepos_t frame, float page)
1243 frame -= (framepos_t) page;
1248 reset_x_origin (frame);
1253 Editor::update_title ()
1255 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1257 if (!own_window()) {
1262 bool dirty = _session->dirty();
1264 string session_name;
1266 if (_session->snap_name() != _session->name()) {
1267 session_name = _session->snap_name();
1269 session_name = _session->name();
1273 session_name = "*" + session_name;
1276 WindowTitle title(session_name);
1277 title += Glib::get_application_name();
1278 own_window()->set_title (title.get_string());
1280 /* ::session_going_away() will have taken care of it */
1285 Editor::set_session (Session *t)
1287 SessionHandlePtr::set_session (t);
1293 _playlist_selector->set_session (_session);
1294 nudge_clock->set_session (_session);
1295 _summary->set_session (_session);
1296 _group_tabs->set_session (_session);
1297 _route_groups->set_session (_session);
1298 _regions->set_session (_session);
1299 _snapshots->set_session (_session);
1300 _routes->set_session (_session);
1301 _locations->set_session (_session);
1303 if (rhythm_ferret) {
1304 rhythm_ferret->set_session (_session);
1307 if (analysis_window) {
1308 analysis_window->set_session (_session);
1312 sfbrowser->set_session (_session);
1315 compute_fixed_ruler_scale ();
1317 /* Make sure we have auto loop and auto punch ranges */
1319 Location* loc = _session->locations()->auto_loop_location();
1321 loc->set_name (_("Loop"));
1324 loc = _session->locations()->auto_punch_location();
1327 loc->set_name (_("Punch"));
1330 refresh_location_display ();
1332 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1333 the selected Marker; this needs the LocationMarker list to be available.
1335 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1336 set_state (*node, Stateful::loading_state_version);
1338 /* catch up with the playhead */
1340 _session->request_locate (playhead_cursor->current_frame ());
1341 _pending_initial_locate = true;
1345 /* These signals can all be emitted by a non-GUI thread. Therefore the
1346 handlers for them must not attempt to directly interact with the GUI,
1347 but use PBD::Signal<T>::connect() which accepts an event loop
1348 ("context") where the handler will be asked to run.
1351 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1352 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1353 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1354 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1355 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1356 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1357 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1358 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1359 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1360 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1361 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1362 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1363 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1365 playhead_cursor->show ();
1367 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1368 Config->map_parameters (pc);
1369 _session->config.map_parameters (pc);
1371 restore_ruler_visibility ();
1372 //tempo_map_changed (PropertyChange (0));
1373 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1375 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1376 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1379 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1380 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1383 switch (_snap_type) {
1384 case SnapToRegionStart:
1385 case SnapToRegionEnd:
1386 case SnapToRegionSync:
1387 case SnapToRegionBoundary:
1388 build_region_boundary_cache ();
1395 /* register for undo history */
1396 _session->register_with_memento_command_factory(id(), this);
1397 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1399 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1401 start_updating_meters ();
1405 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1407 if (a->get_name() == "RegionMenu") {
1408 /* When the main menu's region menu is opened, we setup the actions so that they look right
1409 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1410 so we resensitize all region actions when the entered regionview or the region selection
1411 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1412 happens after the region context menu is opened. So we set a flag here, too.
1416 sensitize_the_right_region_actions ();
1417 _last_region_menu_was_main = true;
1422 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1424 using namespace Menu_Helpers;
1426 void (Editor::*emf)(FadeShape);
1427 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1430 images = &_xfade_in_images;
1431 emf = &Editor::set_fade_in_shape;
1433 images = &_xfade_out_images;
1434 emf = &Editor::set_fade_out_shape;
1439 _("Linear (for highly correlated material)"),
1440 *(*images)[FadeLinear],
1441 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1445 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1449 _("Constant power"),
1450 *(*images)[FadeConstantPower],
1451 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1454 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1459 *(*images)[FadeSymmetric],
1460 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1464 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1469 *(*images)[FadeSlow],
1470 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1473 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1478 *(*images)[FadeFast],
1479 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1482 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1485 /** Pop up a context menu for when the user clicks on a start crossfade */
1487 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1489 using namespace Menu_Helpers;
1490 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1495 MenuList& items (xfade_in_context_menu.items());
1498 if (arv->audio_region()->fade_in_active()) {
1499 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1501 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1504 items.push_back (SeparatorElem());
1505 fill_xfade_menu (items, true);
1507 xfade_in_context_menu.popup (button, time);
1510 /** Pop up a context menu for when the user clicks on an end crossfade */
1512 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1514 using namespace Menu_Helpers;
1515 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1520 MenuList& items (xfade_out_context_menu.items());
1523 if (arv->audio_region()->fade_out_active()) {
1524 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1526 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1529 items.push_back (SeparatorElem());
1530 fill_xfade_menu (items, false);
1532 xfade_out_context_menu.popup (button, time);
1536 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1538 using namespace Menu_Helpers;
1539 Menu* (Editor::*build_menu_function)();
1542 switch (item_type) {
1544 case RegionViewName:
1545 case RegionViewNameHighlight:
1546 case LeftFrameHandle:
1547 case RightFrameHandle:
1548 if (with_selection) {
1549 build_menu_function = &Editor::build_track_selection_context_menu;
1551 build_menu_function = &Editor::build_track_region_context_menu;
1556 if (with_selection) {
1557 build_menu_function = &Editor::build_track_selection_context_menu;
1559 build_menu_function = &Editor::build_track_context_menu;
1564 if (clicked_routeview->track()) {
1565 build_menu_function = &Editor::build_track_context_menu;
1567 build_menu_function = &Editor::build_track_bus_context_menu;
1572 /* probably shouldn't happen but if it does, we don't care */
1576 menu = (this->*build_menu_function)();
1577 menu->set_name ("ArdourContextMenu");
1579 /* now handle specific situations */
1581 switch (item_type) {
1583 case RegionViewName:
1584 case RegionViewNameHighlight:
1585 case LeftFrameHandle:
1586 case RightFrameHandle:
1587 if (!with_selection) {
1588 if (region_edit_menu_split_item) {
1589 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1590 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1592 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1595 if (region_edit_menu_split_multichannel_item) {
1596 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1597 region_edit_menu_split_multichannel_item->set_sensitive (true);
1599 region_edit_menu_split_multichannel_item->set_sensitive (false);
1612 /* probably shouldn't happen but if it does, we don't care */
1616 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1618 /* Bounce to disk */
1620 using namespace Menu_Helpers;
1621 MenuList& edit_items = menu->items();
1623 edit_items.push_back (SeparatorElem());
1625 switch (clicked_routeview->audio_track()->freeze_state()) {
1626 case AudioTrack::NoFreeze:
1627 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1630 case AudioTrack::Frozen:
1631 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1634 case AudioTrack::UnFrozen:
1635 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1641 if (item_type == StreamItem && clicked_routeview) {
1642 clicked_routeview->build_underlay_menu(menu);
1645 /* When the region menu is opened, we setup the actions so that they look right
1648 sensitize_the_right_region_actions ();
1649 _last_region_menu_was_main = false;
1651 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1652 menu->popup (button, time);
1656 Editor::build_track_context_menu ()
1658 using namespace Menu_Helpers;
1660 MenuList& edit_items = track_context_menu.items();
1663 add_dstream_context_items (edit_items);
1664 return &track_context_menu;
1668 Editor::build_track_bus_context_menu ()
1670 using namespace Menu_Helpers;
1672 MenuList& edit_items = track_context_menu.items();
1675 add_bus_context_items (edit_items);
1676 return &track_context_menu;
1680 Editor::build_track_region_context_menu ()
1682 using namespace Menu_Helpers;
1683 MenuList& edit_items = track_region_context_menu.items();
1686 /* we've just cleared the track region context menu, so the menu that these
1687 two items were on will have disappeared; stop them dangling.
1689 region_edit_menu_split_item = 0;
1690 region_edit_menu_split_multichannel_item = 0;
1692 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1695 boost::shared_ptr<Track> tr;
1696 boost::shared_ptr<Playlist> pl;
1698 if ((tr = rtv->track())) {
1699 add_region_context_items (edit_items, tr);
1703 add_dstream_context_items (edit_items);
1705 return &track_region_context_menu;
1709 Editor::analyze_region_selection ()
1711 if (analysis_window == 0) {
1712 analysis_window = new AnalysisWindow();
1715 analysis_window->set_session(_session);
1717 analysis_window->show_all();
1720 analysis_window->set_regionmode();
1721 analysis_window->analyze();
1723 analysis_window->present();
1727 Editor::analyze_range_selection()
1729 if (analysis_window == 0) {
1730 analysis_window = new AnalysisWindow();
1733 analysis_window->set_session(_session);
1735 analysis_window->show_all();
1738 analysis_window->set_rangemode();
1739 analysis_window->analyze();
1741 analysis_window->present();
1745 Editor::build_track_selection_context_menu ()
1747 using namespace Menu_Helpers;
1748 MenuList& edit_items = track_selection_context_menu.items();
1749 edit_items.clear ();
1751 add_selection_context_items (edit_items);
1752 // edit_items.push_back (SeparatorElem());
1753 // add_dstream_context_items (edit_items);
1755 return &track_selection_context_menu;
1759 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1761 using namespace Menu_Helpers;
1763 /* OK, stick the region submenu at the top of the list, and then add
1767 RegionSelection rs = get_regions_from_selection_and_entered ();
1769 string::size_type pos = 0;
1770 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1772 /* we have to hack up the region name because "_" has a special
1773 meaning for menu titles.
1776 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1777 menu_item_name.replace (pos, 1, "__");
1781 if (_popup_region_menu_item == 0) {
1782 _popup_region_menu_item = new MenuItem (menu_item_name);
1783 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1784 _popup_region_menu_item->show ();
1786 _popup_region_menu_item->set_label (menu_item_name);
1789 /* No latering allowed in later is higher layering model */
1790 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1791 if (act && Config->get_layer_model() == LaterHigher) {
1792 act->set_sensitive (false);
1794 act->set_sensitive (true);
1797 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1799 edit_items.push_back (*_popup_region_menu_item);
1800 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1801 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1803 edit_items.push_back (SeparatorElem());
1806 /** Add context menu items relevant to selection ranges.
1807 * @param edit_items List to add the items to.
1810 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1812 using namespace Menu_Helpers;
1814 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1815 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1817 edit_items.push_back (SeparatorElem());
1818 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1820 edit_items.push_back (SeparatorElem());
1821 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1823 edit_items.push_back (SeparatorElem());
1825 edit_items.push_back (
1827 _("Move Range Start to Previous Region Boundary"),
1828 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1832 edit_items.push_back (
1834 _("Move Range Start to Next Region Boundary"),
1835 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1839 edit_items.push_back (
1841 _("Move Range End to Previous Region Boundary"),
1842 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1846 edit_items.push_back (
1848 _("Move Range End to Next Region Boundary"),
1849 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1853 edit_items.push_back (SeparatorElem());
1854 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1855 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1857 edit_items.push_back (SeparatorElem());
1858 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1860 edit_items.push_back (SeparatorElem());
1861 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1862 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1863 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1865 edit_items.push_back (SeparatorElem());
1866 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1868 edit_items.push_back (SeparatorElem());
1869 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1870 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1872 edit_items.push_back (SeparatorElem());
1873 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1874 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1875 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1876 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1877 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1878 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1879 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1885 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1887 using namespace Menu_Helpers;
1891 Menu *play_menu = manage (new Menu);
1892 MenuList& play_items = play_menu->items();
1893 play_menu->set_name ("ArdourContextMenu");
1895 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1896 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1897 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1898 play_items.push_back (SeparatorElem());
1899 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1901 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1905 Menu *select_menu = manage (new Menu);
1906 MenuList& select_items = select_menu->items();
1907 select_menu->set_name ("ArdourContextMenu");
1909 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1910 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1911 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1912 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1913 select_items.push_back (SeparatorElem());
1914 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1915 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1916 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
1917 select_items.push_back (SeparatorElem());
1918 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
1919 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
1920 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1921 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1922 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1923 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1924 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1926 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1930 Menu *cutnpaste_menu = manage (new Menu);
1931 MenuList& cutnpaste_items = cutnpaste_menu->items();
1932 cutnpaste_menu->set_name ("ArdourContextMenu");
1934 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1935 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1936 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1938 cutnpaste_items.push_back (SeparatorElem());
1940 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1941 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1943 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1945 /* Adding new material */
1947 edit_items.push_back (SeparatorElem());
1948 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1949 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1953 Menu *nudge_menu = manage (new Menu());
1954 MenuList& nudge_items = nudge_menu->items();
1955 nudge_menu->set_name ("ArdourContextMenu");
1957 edit_items.push_back (SeparatorElem());
1958 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1959 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1960 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1961 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1963 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1967 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1969 using namespace Menu_Helpers;
1973 Menu *play_menu = manage (new Menu);
1974 MenuList& play_items = play_menu->items();
1975 play_menu->set_name ("ArdourContextMenu");
1977 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1978 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1979 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1983 Menu *select_menu = manage (new Menu);
1984 MenuList& select_items = select_menu->items();
1985 select_menu->set_name ("ArdourContextMenu");
1987 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1988 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1989 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1990 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1991 select_items.push_back (SeparatorElem());
1992 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
1993 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
1994 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1995 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1997 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2001 Menu *cutnpaste_menu = manage (new Menu);
2002 MenuList& cutnpaste_items = cutnpaste_menu->items();
2003 cutnpaste_menu->set_name ("ArdourContextMenu");
2005 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2006 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2007 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2009 Menu *nudge_menu = manage (new Menu());
2010 MenuList& nudge_items = nudge_menu->items();
2011 nudge_menu->set_name ("ArdourContextMenu");
2013 edit_items.push_back (SeparatorElem());
2014 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2015 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2016 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2017 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2019 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2023 Editor::snap_type() const
2029 Editor::snap_mode() const
2035 Editor::set_snap_to (SnapType st)
2037 unsigned int snap_ind = (unsigned int)st;
2039 if (internal_editing()) {
2040 internal_snap_type = st;
2042 pre_internal_snap_type = st;
2047 if (snap_ind > snap_type_strings.size() - 1) {
2049 _snap_type = (SnapType)snap_ind;
2052 string str = snap_type_strings[snap_ind];
2054 if (str != snap_type_selector.get_text()) {
2055 snap_type_selector.set_text (str);
2060 switch (_snap_type) {
2061 case SnapToBeatDiv128:
2062 case SnapToBeatDiv64:
2063 case SnapToBeatDiv32:
2064 case SnapToBeatDiv28:
2065 case SnapToBeatDiv24:
2066 case SnapToBeatDiv20:
2067 case SnapToBeatDiv16:
2068 case SnapToBeatDiv14:
2069 case SnapToBeatDiv12:
2070 case SnapToBeatDiv10:
2071 case SnapToBeatDiv8:
2072 case SnapToBeatDiv7:
2073 case SnapToBeatDiv6:
2074 case SnapToBeatDiv5:
2075 case SnapToBeatDiv4:
2076 case SnapToBeatDiv3:
2077 case SnapToBeatDiv2: {
2078 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2079 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2081 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2082 current_bbt_points_begin, current_bbt_points_end);
2083 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2084 current_bbt_points_begin, current_bbt_points_end);
2085 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2089 case SnapToRegionStart:
2090 case SnapToRegionEnd:
2091 case SnapToRegionSync:
2092 case SnapToRegionBoundary:
2093 build_region_boundary_cache ();
2101 redisplay_tempo (false);
2103 SnapChanged (); /* EMIT SIGNAL */
2107 Editor::set_snap_mode (SnapMode mode)
2109 string str = snap_mode_strings[(int)mode];
2111 if (internal_editing()) {
2112 internal_snap_mode = mode;
2114 pre_internal_snap_mode = mode;
2119 if (str != snap_mode_selector.get_text ()) {
2120 snap_mode_selector.set_text (str);
2127 Editor::set_edit_point_preference (EditPoint ep, bool force)
2129 bool changed = (_edit_point != ep);
2132 if (Profile->get_mixbus())
2133 if (ep == EditAtSelectedMarker)
2134 ep = EditAtPlayhead;
2136 string str = edit_point_strings[(int)ep];
2137 if (str != edit_point_selector.get_text ()) {
2138 edit_point_selector.set_text (str);
2141 update_all_enter_cursors();
2143 if (!force && !changed) {
2147 const char* action=NULL;
2149 switch (_edit_point) {
2150 case EditAtPlayhead:
2151 action = "edit-at-playhead";
2153 case EditAtSelectedMarker:
2154 action = "edit-at-marker";
2157 action = "edit-at-mouse";
2161 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2163 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2167 bool in_track_canvas;
2169 if (!mouse_frame (foo, in_track_canvas)) {
2170 in_track_canvas = false;
2173 reset_canvas_action_sensitivity (in_track_canvas);
2179 Editor::set_state (const XMLNode& node, int version)
2181 const XMLProperty* prop;
2184 Tabbable::set_state (node, version);
2186 if (_session && (prop = node.property ("playhead"))) {
2188 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2190 playhead_cursor->set_position (pos);
2192 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2193 playhead_cursor->set_position (0);
2196 playhead_cursor->set_position (0);
2199 if ((prop = node.property ("mixer-width"))) {
2200 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2203 if ((prop = node.property ("zoom-focus"))) {
2204 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2207 if ((prop = node.property ("zoom"))) {
2208 /* older versions of ardour used floating point samples_per_pixel */
2209 double f = PBD::atof (prop->value());
2210 reset_zoom (llrintf (f));
2212 reset_zoom (samples_per_pixel);
2215 if ((prop = node.property ("visible-track-count"))) {
2216 set_visible_track_count (PBD::atoi (prop->value()));
2219 if ((prop = node.property ("snap-to"))) {
2220 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2223 if ((prop = node.property ("snap-mode"))) {
2224 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2227 if ((prop = node.property ("internal-snap-to"))) {
2228 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2231 if ((prop = node.property ("internal-snap-mode"))) {
2232 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2235 if ((prop = node.property ("pre-internal-snap-to"))) {
2236 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2239 if ((prop = node.property ("pre-internal-snap-mode"))) {
2240 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2243 if ((prop = node.property ("mouse-mode"))) {
2244 MouseMode m = str2mousemode(prop->value());
2245 set_mouse_mode (m, true);
2247 set_mouse_mode (MouseObject, true);
2250 if ((prop = node.property ("left-frame")) != 0) {
2252 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2256 reset_x_origin (pos);
2260 if ((prop = node.property ("y-origin")) != 0) {
2261 reset_y_origin (atof (prop->value ()));
2264 if ((prop = node.property ("join-object-range"))) {
2265 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2266 bool yn = string_is_affirmative (prop->value());
2268 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2269 tact->set_active (!yn);
2270 tact->set_active (yn);
2272 set_mouse_mode(mouse_mode, true);
2275 if ((prop = node.property ("edit-point"))) {
2276 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2279 if ((prop = node.property ("show-measures"))) {
2280 bool yn = string_is_affirmative (prop->value());
2281 _show_measures = yn;
2284 if ((prop = node.property ("follow-playhead"))) {
2285 bool yn = string_is_affirmative (prop->value());
2286 set_follow_playhead (yn);
2289 if ((prop = node.property ("stationary-playhead"))) {
2290 bool yn = string_is_affirmative (prop->value());
2291 set_stationary_playhead (yn);
2294 if ((prop = node.property ("region-list-sort-type"))) {
2295 RegionListSortType st;
2296 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2299 if ((prop = node.property ("show-editor-mixer"))) {
2301 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2304 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2305 bool yn = string_is_affirmative (prop->value());
2307 /* do it twice to force the change */
2309 tact->set_active (!yn);
2310 tact->set_active (yn);
2313 if ((prop = node.property ("show-editor-list"))) {
2315 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2318 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2319 bool yn = string_is_affirmative (prop->value());
2321 /* do it twice to force the change */
2323 tact->set_active (!yn);
2324 tact->set_active (yn);
2327 if ((prop = node.property (X_("editor-list-page")))) {
2328 _the_notebook.set_current_page (atoi (prop->value ()));
2331 if ((prop = node.property (X_("show-marker-lines")))) {
2332 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2334 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2335 bool yn = string_is_affirmative (prop->value ());
2337 tact->set_active (!yn);
2338 tact->set_active (yn);
2341 XMLNodeList children = node.children ();
2342 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2343 selection->set_state (**i, Stateful::current_state_version);
2344 _regions->set_state (**i);
2347 if ((prop = node.property ("maximised"))) {
2348 bool yn = string_is_affirmative (prop->value());
2349 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2351 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2352 bool fs = tact && tact->get_active();
2354 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2358 if ((prop = node.property ("nudge-clock-value"))) {
2360 sscanf (prop->value().c_str(), "%" PRId64, &f);
2361 nudge_clock->set (f);
2363 nudge_clock->set_mode (AudioClock::Timecode);
2364 nudge_clock->set (_session->frame_rate() * 5, true);
2369 * Not all properties may have been in XML, but
2370 * those that are linked to a private variable may need changing
2375 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2377 yn = _show_measures;
2378 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2379 /* do it twice to force the change */
2380 tact->set_active (!yn);
2381 tact->set_active (yn);
2384 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2385 yn = _follow_playhead;
2387 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2388 if (tact->get_active() != yn) {
2389 tact->set_active (yn);
2393 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2394 yn = _stationary_playhead;
2396 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2397 if (tact->get_active() != yn) {
2398 tact->set_active (yn);
2407 Editor::get_state ()
2409 XMLNode* node = new XMLNode (X_("Editor"));
2412 id().print (buf, sizeof (buf));
2413 node->add_property ("id", buf);
2415 node->add_child_nocopy (Tabbable::get_state());
2417 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2418 node->add_property("edit-horizontal-pane-pos", string(buf));
2419 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2420 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2421 node->add_property("edit-vertical-pane-pos", string(buf));
2423 maybe_add_mixer_strip_width (*node);
2425 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2427 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2428 node->add_property ("zoom", buf);
2429 node->add_property ("snap-to", enum_2_string (_snap_type));
2430 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2431 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2432 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2433 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2434 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2435 node->add_property ("edit-point", enum_2_string (_edit_point));
2436 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2437 node->add_property ("visible-track-count", buf);
2439 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2440 node->add_property ("playhead", buf);
2441 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2442 node->add_property ("left-frame", buf);
2443 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2444 node->add_property ("y-origin", buf);
2446 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2447 node->add_property ("maximised", _maximised ? "yes" : "no");
2448 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2449 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2450 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2451 node->add_property ("mouse-mode", enum2str(mouse_mode));
2452 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2454 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2456 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2457 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2460 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2462 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2463 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2466 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2467 node->add_property (X_("editor-list-page"), buf);
2469 if (button_bindings) {
2470 XMLNode* bb = new XMLNode (X_("Buttons"));
2471 button_bindings->save (*bb);
2472 node->add_child_nocopy (*bb);
2475 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2477 node->add_child_nocopy (selection->get_state ());
2478 node->add_child_nocopy (_regions->get_state ());
2480 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2481 node->add_property ("nudge-clock-value", buf);
2486 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2487 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2489 * @return pair: TimeAxisView that y is over, layer index.
2491 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2492 * in stacked or expanded region display mode, otherwise 0.
2494 std::pair<TimeAxisView *, double>
2495 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2497 if (!trackview_relative_offset) {
2498 y -= _trackview_group->canvas_origin().y;
2502 return std::make_pair ( (TimeAxisView *) 0, 0);
2505 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2507 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2514 return std::make_pair ( (TimeAxisView *) 0, 0);
2517 /** Snap a position to the grid, if appropriate, taking into account current
2518 * grid settings and also the state of any snap modifier keys that may be pressed.
2519 * @param start Position to snap.
2520 * @param event Event to get current key modifier information from, or 0.
2523 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2525 if (!_session || !event) {
2529 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2530 if (_snap_mode == SnapOff) {
2531 snap_to_internal (start, direction, for_mark);
2534 if (_snap_mode != SnapOff) {
2535 snap_to_internal (start, direction, for_mark);
2536 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2537 /* SnapOff, but we pressed the snap_delta modifier */
2538 snap_to_internal (start, direction, for_mark);
2544 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2546 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2550 snap_to_internal (start, direction, for_mark, ensure_snap);
2554 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2556 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2557 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2559 switch (_snap_type) {
2560 case SnapToTimecodeFrame:
2561 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2562 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2563 /* start is already on a whole timecode frame, do nothing */
2564 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2565 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2567 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2571 case SnapToTimecodeSeconds:
2572 if (_session->config.get_timecode_offset_negative()) {
2573 start += _session->config.get_timecode_offset ();
2575 start -= _session->config.get_timecode_offset ();
2577 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2578 (start % one_timecode_second == 0)) {
2579 /* start is already on a whole second, do nothing */
2580 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2581 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2583 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2586 if (_session->config.get_timecode_offset_negative()) {
2587 start -= _session->config.get_timecode_offset ();
2589 start += _session->config.get_timecode_offset ();
2593 case SnapToTimecodeMinutes:
2594 if (_session->config.get_timecode_offset_negative()) {
2595 start += _session->config.get_timecode_offset ();
2597 start -= _session->config.get_timecode_offset ();
2599 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2600 (start % one_timecode_minute == 0)) {
2601 /* start is already on a whole minute, do nothing */
2602 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2603 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2605 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2607 if (_session->config.get_timecode_offset_negative()) {
2608 start -= _session->config.get_timecode_offset ();
2610 start += _session->config.get_timecode_offset ();
2614 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2615 abort(); /*NOTREACHED*/
2620 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2622 const framepos_t one_second = _session->frame_rate();
2623 const framepos_t one_minute = _session->frame_rate() * 60;
2624 framepos_t presnap = start;
2628 switch (_snap_type) {
2629 case SnapToTimecodeFrame:
2630 case SnapToTimecodeSeconds:
2631 case SnapToTimecodeMinutes:
2632 return timecode_snap_to_internal (start, direction, for_mark);
2635 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2636 start % (one_second/75) == 0) {
2637 /* start is already on a whole CD frame, do nothing */
2638 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2639 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2641 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2646 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2647 start % one_second == 0) {
2648 /* start is already on a whole second, do nothing */
2649 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2650 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2652 start = (framepos_t) floor ((double) start / one_second) * one_second;
2657 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2658 start % one_minute == 0) {
2659 /* start is already on a whole minute, do nothing */
2660 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2661 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2663 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2668 start = _session->tempo_map().round_to_bar (start, direction);
2672 start = _session->tempo_map().round_to_beat (start, direction);
2675 case SnapToBeatDiv128:
2676 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2678 case SnapToBeatDiv64:
2679 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2681 case SnapToBeatDiv32:
2682 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2684 case SnapToBeatDiv28:
2685 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2687 case SnapToBeatDiv24:
2688 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2690 case SnapToBeatDiv20:
2691 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2693 case SnapToBeatDiv16:
2694 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2696 case SnapToBeatDiv14:
2697 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2699 case SnapToBeatDiv12:
2700 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2702 case SnapToBeatDiv10:
2703 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2705 case SnapToBeatDiv8:
2706 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2708 case SnapToBeatDiv7:
2709 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2711 case SnapToBeatDiv6:
2712 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2714 case SnapToBeatDiv5:
2715 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2717 case SnapToBeatDiv4:
2718 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2720 case SnapToBeatDiv3:
2721 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2723 case SnapToBeatDiv2:
2724 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2732 _session->locations()->marks_either_side (start, before, after);
2734 if (before == max_framepos && after == max_framepos) {
2735 /* No marks to snap to, so just don't snap */
2737 } else if (before == max_framepos) {
2739 } else if (after == max_framepos) {
2741 } else if (before != max_framepos && after != max_framepos) {
2742 /* have before and after */
2743 if ((start - before) < (after - start)) {
2752 case SnapToRegionStart:
2753 case SnapToRegionEnd:
2754 case SnapToRegionSync:
2755 case SnapToRegionBoundary:
2756 if (!region_boundary_cache.empty()) {
2758 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2759 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2761 if (direction > 0) {
2762 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2764 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2767 if (next != region_boundary_cache.begin ()) {
2772 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2773 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2775 if (start > (p + n) / 2) {
2784 switch (_snap_mode) {
2794 if (presnap > start) {
2795 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2799 } else if (presnap < start) {
2800 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2806 /* handled at entry */
2814 Editor::setup_toolbar ()
2816 HBox* mode_box = manage(new HBox);
2817 mode_box->set_border_width (2);
2818 mode_box->set_spacing(2);
2820 HBox* mouse_mode_box = manage (new HBox);
2821 HBox* mouse_mode_hbox = manage (new HBox);
2822 VBox* mouse_mode_vbox = manage (new VBox);
2823 Alignment* mouse_mode_align = manage (new Alignment);
2825 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2826 mouse_mode_size_group->add_widget (smart_mode_button);
2827 mouse_mode_size_group->add_widget (mouse_move_button);
2828 mouse_mode_size_group->add_widget (mouse_cut_button);
2829 mouse_mode_size_group->add_widget (mouse_select_button);
2830 mouse_mode_size_group->add_widget (mouse_timefx_button);
2831 mouse_mode_size_group->add_widget (mouse_audition_button);
2832 mouse_mode_size_group->add_widget (mouse_draw_button);
2833 mouse_mode_size_group->add_widget (mouse_content_button);
2835 mouse_mode_size_group->add_widget (zoom_in_button);
2836 mouse_mode_size_group->add_widget (zoom_out_button);
2837 mouse_mode_size_group->add_widget (zoom_preset_selector);
2838 mouse_mode_size_group->add_widget (zoom_out_full_button);
2839 mouse_mode_size_group->add_widget (zoom_focus_selector);
2841 mouse_mode_size_group->add_widget (tav_shrink_button);
2842 mouse_mode_size_group->add_widget (tav_expand_button);
2843 mouse_mode_size_group->add_widget (visible_tracks_selector);
2845 mouse_mode_size_group->add_widget (snap_type_selector);
2846 mouse_mode_size_group->add_widget (snap_mode_selector);
2848 mouse_mode_size_group->add_widget (edit_point_selector);
2849 mouse_mode_size_group->add_widget (edit_mode_selector);
2851 mouse_mode_size_group->add_widget (*nudge_clock);
2852 mouse_mode_size_group->add_widget (nudge_forward_button);
2853 mouse_mode_size_group->add_widget (nudge_backward_button);
2855 mouse_mode_hbox->set_spacing (2);
2857 if (!ARDOUR::Profile->get_trx()) {
2858 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2861 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2862 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2864 if (!ARDOUR::Profile->get_mixbus()) {
2865 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2868 if (!ARDOUR::Profile->get_trx()) {
2869 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2870 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2871 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2872 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2875 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2877 mouse_mode_align->add (*mouse_mode_vbox);
2878 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2880 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2882 edit_mode_selector.set_name ("mouse mode button");
2884 if (!ARDOUR::Profile->get_trx()) {
2885 mode_box->pack_start (edit_mode_selector, false, false);
2888 mode_box->pack_start (*mouse_mode_box, false, false);
2892 _zoom_box.set_spacing (2);
2893 _zoom_box.set_border_width (2);
2897 zoom_preset_selector.set_name ("zoom button");
2898 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2899 zoom_preset_selector.set_size_request (42, -1);
2901 zoom_in_button.set_name ("zoom button");
2902 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
2903 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2904 zoom_in_button.set_related_action (act);
2906 zoom_out_button.set_name ("zoom button");
2907 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
2908 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2909 zoom_out_button.set_related_action (act);
2911 zoom_out_full_button.set_name ("zoom button");
2912 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
2913 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2914 zoom_out_full_button.set_related_action (act);
2916 zoom_focus_selector.set_name ("zoom button");
2918 if (ARDOUR::Profile->get_mixbus()) {
2919 _zoom_box.pack_start (zoom_preset_selector, false, false);
2920 } else if (ARDOUR::Profile->get_trx()) {
2921 mode_box->pack_start (zoom_out_button, false, false);
2922 mode_box->pack_start (zoom_in_button, false, false);
2924 _zoom_box.pack_start (zoom_out_button, false, false);
2925 _zoom_box.pack_start (zoom_in_button, false, false);
2926 _zoom_box.pack_start (zoom_out_full_button, false, false);
2927 _zoom_box.pack_start (zoom_focus_selector, false, false);
2930 /* Track zoom buttons */
2931 visible_tracks_selector.set_name ("zoom button");
2932 if (Profile->get_mixbus()) {
2933 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2934 visible_tracks_selector.set_size_request (42, -1);
2936 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2939 tav_expand_button.set_name ("zoom button");
2940 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
2941 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2942 tav_expand_button.set_related_action (act);
2944 tav_shrink_button.set_name ("zoom button");
2945 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
2946 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2947 tav_shrink_button.set_related_action (act);
2949 if (ARDOUR::Profile->get_mixbus()) {
2950 _zoom_box.pack_start (visible_tracks_selector);
2951 } else if (ARDOUR::Profile->get_trx()) {
2952 _zoom_box.pack_start (tav_shrink_button);
2953 _zoom_box.pack_start (tav_expand_button);
2955 _zoom_box.pack_start (visible_tracks_selector);
2956 _zoom_box.pack_start (tav_shrink_button);
2957 _zoom_box.pack_start (tav_expand_button);
2960 snap_box.set_spacing (2);
2961 snap_box.set_border_width (2);
2963 snap_type_selector.set_name ("mouse mode button");
2965 snap_mode_selector.set_name ("mouse mode button");
2967 edit_point_selector.set_name ("mouse mode button");
2969 snap_box.pack_start (snap_mode_selector, false, false);
2970 snap_box.pack_start (snap_type_selector, false, false);
2971 snap_box.pack_start (edit_point_selector, false, false);
2975 HBox *nudge_box = manage (new HBox);
2976 nudge_box->set_spacing (2);
2977 nudge_box->set_border_width (2);
2979 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2980 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2982 nudge_box->pack_start (nudge_backward_button, false, false);
2983 nudge_box->pack_start (nudge_forward_button, false, false);
2984 nudge_box->pack_start (*nudge_clock, false, false);
2987 /* Pack everything in... */
2989 HBox* hbox = manage (new HBox);
2990 hbox->set_spacing(2);
2992 toolbar_hbox.set_spacing (2);
2993 toolbar_hbox.set_border_width (1);
2995 toolbar_hbox.pack_start (*mode_box, false, false);
2996 if (!ARDOUR::Profile->get_trx()) {
2997 toolbar_hbox.pack_start (_zoom_box, false, false);
2998 toolbar_hbox.pack_start (*hbox, false, false);
3001 if (!ARDOUR::Profile->get_trx()) {
3002 hbox->pack_start (snap_box, false, false);
3003 hbox->pack_start (*nudge_box, false, false);
3008 toolbar_base.set_name ("ToolBarBase");
3009 toolbar_base.add (toolbar_hbox);
3011 _toolbar_viewport.add (toolbar_base);
3012 /* stick to the required height but allow width to vary if there's not enough room */
3013 _toolbar_viewport.set_size_request (1, -1);
3015 toolbar_frame.set_shadow_type (SHADOW_OUT);
3016 toolbar_frame.set_name ("BaseFrame");
3017 toolbar_frame.add (_toolbar_viewport);
3021 Editor::build_edit_point_menu ()
3023 using namespace Menu_Helpers;
3025 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3026 if(!Profile->get_mixbus())
3027 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3028 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3030 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3034 Editor::build_edit_mode_menu ()
3036 using namespace Menu_Helpers;
3038 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3039 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3040 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3041 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3043 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3047 Editor::build_snap_mode_menu ()
3049 using namespace Menu_Helpers;
3051 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3052 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3053 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3055 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3059 Editor::build_snap_type_menu ()
3061 using namespace Menu_Helpers;
3063 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3064 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3065 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3066 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3067 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3068 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3069 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3070 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3071 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3072 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3073 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3074 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3075 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3076 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3077 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3078 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3079 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3080 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3081 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3082 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3083 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3084 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3085 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3086 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3087 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3088 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3089 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3090 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3091 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3092 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3094 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3099 Editor::setup_tooltips ()
3101 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3102 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3103 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3104 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3105 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3106 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3107 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3108 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3109 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3110 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3111 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3112 set_tooltip (zoom_in_button, _("Zoom In"));
3113 set_tooltip (zoom_out_button, _("Zoom Out"));
3114 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3115 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3116 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3117 set_tooltip (tav_expand_button, _("Expand Tracks"));
3118 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3119 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3120 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3121 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3122 set_tooltip (edit_point_selector, _("Edit Point"));
3123 set_tooltip (edit_mode_selector, _("Edit Mode"));
3124 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3128 Editor::convert_drop_to_paths (
3129 vector<string>& paths,
3130 const RefPtr<Gdk::DragContext>& /*context*/,
3133 const SelectionData& data,
3137 if (_session == 0) {
3141 vector<string> uris = data.get_uris();
3145 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3146 are actually URI lists. So do it by hand.
3149 if (data.get_target() != "text/plain") {
3153 /* Parse the "uri-list" format that Nautilus provides,
3154 where each pathname is delimited by \r\n.
3156 THERE MAY BE NO NULL TERMINATING CHAR!!!
3159 string txt = data.get_text();
3163 p = (char *) malloc (txt.length() + 1);
3164 txt.copy (p, txt.length(), 0);
3165 p[txt.length()] = '\0';
3171 while (g_ascii_isspace (*p))
3175 while (*q && (*q != '\n') && (*q != '\r')) {
3182 while (q > p && g_ascii_isspace (*q))
3187 uris.push_back (string (p, q - p + 1));
3191 p = strchr (p, '\n');
3203 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3204 if ((*i).substr (0,7) == "file://") {
3205 paths.push_back (Glib::filename_from_uri (*i));
3213 Editor::new_tempo_section ()
3218 Editor::map_transport_state ()
3220 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3222 if (_session && _session->transport_stopped()) {
3223 have_pending_keyboard_selection = false;
3226 update_loop_range_view ();
3232 Editor::begin_selection_op_history ()
3234 selection_op_cmd_depth = 0;
3235 selection_op_history_it = 0;
3237 while(!selection_op_history.empty()) {
3238 delete selection_op_history.front();
3239 selection_op_history.pop_front();
3242 selection_undo_action->set_sensitive (false);
3243 selection_redo_action->set_sensitive (false);
3244 selection_op_history.push_front (&_selection_memento->get_state ());
3248 Editor::begin_reversible_selection_op (string name)
3251 //cerr << name << endl;
3252 /* begin/commit pairs can be nested */
3253 selection_op_cmd_depth++;
3258 Editor::commit_reversible_selection_op ()
3261 if (selection_op_cmd_depth == 1) {
3263 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3265 The user has undone some selection ops and then made a new one,
3266 making anything earlier in the list invalid.
3269 list<XMLNode *>::iterator it = selection_op_history.begin();
3270 list<XMLNode *>::iterator e_it = it;
3271 advance (e_it, selection_op_history_it);
3273 for ( ; it != e_it; ++it) {
3276 selection_op_history.erase (selection_op_history.begin(), e_it);
3279 selection_op_history.push_front (&_selection_memento->get_state ());
3280 selection_op_history_it = 0;
3282 selection_undo_action->set_sensitive (true);
3283 selection_redo_action->set_sensitive (false);
3286 if (selection_op_cmd_depth > 0) {
3287 selection_op_cmd_depth--;
3293 Editor::undo_selection_op ()
3296 selection_op_history_it++;
3298 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3299 if (n == selection_op_history_it) {
3300 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3301 selection_redo_action->set_sensitive (true);
3305 /* is there an earlier entry? */
3306 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3307 selection_undo_action->set_sensitive (false);
3313 Editor::redo_selection_op ()
3316 if (selection_op_history_it > 0) {
3317 selection_op_history_it--;
3320 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3321 if (n == selection_op_history_it) {
3322 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3323 selection_undo_action->set_sensitive (true);
3328 if (selection_op_history_it == 0) {
3329 selection_redo_action->set_sensitive (false);
3335 Editor::begin_reversible_command (string name)
3338 before.push_back (&_selection_memento->get_state ());
3339 _session->begin_reversible_command (name);
3344 Editor::begin_reversible_command (GQuark q)
3347 before.push_back (&_selection_memento->get_state ());
3348 _session->begin_reversible_command (q);
3353 Editor::abort_reversible_command ()
3356 while(!before.empty()) {
3357 delete before.front();
3360 _session->abort_reversible_command ();
3365 Editor::commit_reversible_command ()
3368 if (before.size() == 1) {
3369 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3370 redo_action->set_sensitive(false);
3371 undo_action->set_sensitive(true);
3372 begin_selection_op_history ();
3375 if (before.empty()) {
3376 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3381 _session->commit_reversible_command ();
3386 Editor::history_changed ()
3390 if (undo_action && _session) {
3391 if (_session->undo_depth() == 0) {
3392 label = S_("Command|Undo");
3394 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3396 undo_action->property_label() = label;
3399 if (redo_action && _session) {
3400 if (_session->redo_depth() == 0) {
3402 redo_action->set_sensitive (false);
3404 label = string_compose(_("Redo (%1)"), _session->next_redo());
3405 redo_action->set_sensitive (true);
3407 redo_action->property_label() = label;
3412 Editor::duplicate_range (bool with_dialog)
3416 RegionSelection rs = get_regions_from_selection_and_entered ();
3418 if ( selection->time.length() == 0 && rs.empty()) {
3424 ArdourDialog win (_("Duplicate"));
3425 Label label (_("Number of duplications:"));
3426 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3427 SpinButton spinner (adjustment, 0.0, 1);
3430 win.get_vbox()->set_spacing (12);
3431 win.get_vbox()->pack_start (hbox);
3432 hbox.set_border_width (6);
3433 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3435 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3436 place, visually. so do this by hand.
3439 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3440 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3441 spinner.grab_focus();
3447 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3448 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3449 win.set_default_response (RESPONSE_ACCEPT);
3451 spinner.grab_focus ();
3453 switch (win.run ()) {
3454 case RESPONSE_ACCEPT:
3460 times = adjustment.get_value();
3463 if ((current_mouse_mode() == Editing::MouseRange)) {
3464 if (selection->time.length()) {
3465 duplicate_selection (times);
3467 } else if (get_smart_mode()) {
3468 if (selection->time.length()) {
3469 duplicate_selection (times);
3471 duplicate_some_regions (rs, times);
3473 duplicate_some_regions (rs, times);
3478 Editor::set_edit_mode (EditMode m)
3480 Config->set_edit_mode (m);
3484 Editor::cycle_edit_mode ()
3486 switch (Config->get_edit_mode()) {
3488 Config->set_edit_mode (Ripple);
3492 Config->set_edit_mode (Lock);
3495 Config->set_edit_mode (Slide);
3501 Editor::edit_mode_selection_done ( EditMode m )
3503 Config->set_edit_mode ( m );
3507 Editor::snap_type_selection_done (SnapType snaptype)
3509 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3511 ract->set_active ();
3516 Editor::snap_mode_selection_done (SnapMode mode)
3518 RefPtr<RadioAction> ract = snap_mode_action (mode);
3521 ract->set_active (true);
3526 Editor::cycle_edit_point (bool with_marker)
3528 if(Profile->get_mixbus())
3529 with_marker = false;
3531 switch (_edit_point) {
3533 set_edit_point_preference (EditAtPlayhead);
3535 case EditAtPlayhead:
3537 set_edit_point_preference (EditAtSelectedMarker);
3539 set_edit_point_preference (EditAtMouse);
3542 case EditAtSelectedMarker:
3543 set_edit_point_preference (EditAtMouse);
3549 Editor::edit_point_selection_done (EditPoint ep)
3551 set_edit_point_preference ( ep );
3555 Editor::build_zoom_focus_menu ()
3557 using namespace Menu_Helpers;
3559 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3560 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3561 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3562 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3563 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3564 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3566 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3570 Editor::zoom_focus_selection_done ( ZoomFocus f )
3572 RefPtr<RadioAction> ract = zoom_focus_action (f);
3574 ract->set_active ();
3579 Editor::build_track_count_menu ()
3581 using namespace Menu_Helpers;
3583 if (!Profile->get_mixbus()) {
3584 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3585 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3586 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3587 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3588 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3589 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3590 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3591 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3592 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3593 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3594 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3595 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3596 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3598 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3599 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3600 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3601 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3602 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3603 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3604 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3605 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3606 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3607 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3609 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3610 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3611 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3612 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3613 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3614 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3615 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3616 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3617 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3618 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3619 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3624 Editor::set_zoom_preset (int64_t ms)
3627 temporal_zoom_session();
3631 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3632 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3636 Editor::set_visible_track_count (int32_t n)
3638 _visible_track_count = n;
3640 /* if the canvas hasn't really been allocated any size yet, just
3641 record the desired number of visible tracks and return. when canvas
3642 allocation happens, we will get called again and then we can do the
3646 if (_visible_canvas_height <= 1) {
3652 DisplaySuspender ds;
3654 if (_visible_track_count > 0) {
3655 h = trackviews_height() / _visible_track_count;
3656 std::ostringstream s;
3657 s << _visible_track_count;
3659 } else if (_visible_track_count == 0) {
3661 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3662 if ((*i)->marked_for_display()) {
3666 h = trackviews_height() / n;
3669 /* negative value means that the visible track count has
3670 been overridden by explicit track height changes.
3672 visible_tracks_selector.set_text (X_("*"));
3676 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3677 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3680 if (str != visible_tracks_selector.get_text()) {
3681 visible_tracks_selector.set_text (str);
3686 Editor::override_visible_track_count ()
3688 _visible_track_count = -1;
3689 visible_tracks_selector.set_text ( _("*") );
3693 Editor::edit_controls_button_release (GdkEventButton* ev)
3695 if (Keyboard::is_context_menu_event (ev)) {
3696 ARDOUR_UI::instance()->add_route (current_toplevel());
3697 } else if (ev->button == 1) {
3698 selection->clear_tracks ();
3705 Editor::mouse_select_button_release (GdkEventButton* ev)
3707 /* this handles just right-clicks */
3709 if (ev->button != 3) {
3717 Editor::set_zoom_focus (ZoomFocus f)
3719 string str = zoom_focus_strings[(int)f];
3721 if (str != zoom_focus_selector.get_text()) {
3722 zoom_focus_selector.set_text (str);
3725 if (zoom_focus != f) {
3732 Editor::cycle_zoom_focus ()
3734 switch (zoom_focus) {
3736 set_zoom_focus (ZoomFocusRight);
3738 case ZoomFocusRight:
3739 set_zoom_focus (ZoomFocusCenter);
3741 case ZoomFocusCenter:
3742 set_zoom_focus (ZoomFocusPlayhead);
3744 case ZoomFocusPlayhead:
3745 set_zoom_focus (ZoomFocusMouse);
3747 case ZoomFocusMouse:
3748 set_zoom_focus (ZoomFocusEdit);
3751 set_zoom_focus (ZoomFocusLeft);
3757 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3759 /* recover or initialize pane positions. do this here rather than earlier because
3760 we don't want the positions to change the child allocations, which they seem to do.
3766 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3775 XMLNode* geometry = find_named_node (*node, "geometry");
3777 if (which == static_cast<Paned*> (&edit_pane)) {
3779 if (done & Horizontal) {
3783 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3784 _notebook_shrunk = string_is_affirmative (prop->value ());
3787 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3788 /* initial allocation is 90% to canvas, 10% to notebook */
3789 pos = (int) floor (alloc.get_width() * 0.90f);
3790 snprintf (buf, sizeof(buf), "%d", pos);
3792 pos = atoi (prop->value());
3795 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3796 edit_pane.set_position (pos);
3799 done = (Pane) (done | Horizontal);
3801 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3803 if (done & Vertical) {
3807 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3808 /* initial allocation is 90% to canvas, 10% to summary */
3809 pos = (int) floor (alloc.get_height() * 0.90f);
3810 snprintf (buf, sizeof(buf), "%d", pos);
3813 pos = atoi (prop->value());
3816 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3817 editor_summary_pane.set_position (pos);
3820 done = (Pane) (done | Vertical);
3825 Editor::set_show_measures (bool yn)
3827 if (_show_measures != yn) {
3830 if ((_show_measures = yn) == true) {
3832 tempo_lines->show();
3835 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3836 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3838 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3839 draw_measures (begin, end);
3847 Editor::toggle_follow_playhead ()
3849 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3851 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3852 set_follow_playhead (tact->get_active());
3856 /** @param yn true to follow playhead, otherwise false.
3857 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3860 Editor::set_follow_playhead (bool yn, bool catch_up)
3862 if (_follow_playhead != yn) {
3863 if ((_follow_playhead = yn) == true && catch_up) {
3865 reset_x_origin_to_follow_playhead ();
3872 Editor::toggle_stationary_playhead ()
3874 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3876 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3877 set_stationary_playhead (tact->get_active());
3882 Editor::set_stationary_playhead (bool yn)
3884 if (_stationary_playhead != yn) {
3885 if ((_stationary_playhead = yn) == true) {
3887 // FIXME need a 3.0 equivalent of this 2.X call
3888 // update_current_screen ();
3895 Editor::playlist_selector () const
3897 return *_playlist_selector;
3901 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
3903 if (paste_count == 0) {
3904 /* don't bother calculating an offset that will be zero anyway */
3908 /* calculate basic unsnapped multi-paste offset */
3909 framecnt_t offset = paste_count * duration;
3911 /* snap offset so pos + offset is aligned to the grid */
3912 framepos_t offset_pos = pos + offset;
3913 snap_to(offset_pos, RoundUpMaybe);
3914 offset = offset_pos - pos;
3920 Editor::get_grid_beat_divisions(framepos_t position)
3922 switch (_snap_type) {
3923 case SnapToBeatDiv128: return 128;
3924 case SnapToBeatDiv64: return 64;
3925 case SnapToBeatDiv32: return 32;
3926 case SnapToBeatDiv28: return 28;
3927 case SnapToBeatDiv24: return 24;
3928 case SnapToBeatDiv20: return 20;
3929 case SnapToBeatDiv16: return 16;
3930 case SnapToBeatDiv14: return 14;
3931 case SnapToBeatDiv12: return 12;
3932 case SnapToBeatDiv10: return 10;
3933 case SnapToBeatDiv8: return 8;
3934 case SnapToBeatDiv7: return 7;
3935 case SnapToBeatDiv6: return 6;
3936 case SnapToBeatDiv5: return 5;
3937 case SnapToBeatDiv4: return 4;
3938 case SnapToBeatDiv3: return 3;
3939 case SnapToBeatDiv2: return 2;
3946 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3950 const unsigned divisions = get_grid_beat_divisions(position);
3952 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
3955 switch (_snap_type) {
3957 return Evoral::Beats(1.0);
3960 return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
3968 return Evoral::Beats();
3972 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3976 ret = nudge_clock->current_duration (pos);
3977 next = ret + 1; /* XXXX fix me */
3983 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3985 ArdourDialog dialog (_("Playlist Deletion"));
3986 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3987 "If it is kept, its audio files will not be cleaned.\n"
3988 "If it is deleted, audio files used by it alone will be cleaned."),
3991 dialog.set_position (WIN_POS_CENTER);
3992 dialog.get_vbox()->pack_start (label);
3996 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
3997 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3998 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3999 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4000 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4002 // by default gtk uses the left most button
4003 keep->grab_focus ();
4005 switch (dialog.run ()) {
4007 /* keep this and all remaining ones */
4012 /* delete this and all others */
4016 case RESPONSE_ACCEPT:
4017 /* delete the playlist */
4021 case RESPONSE_REJECT:
4022 /* keep the playlist */
4034 Editor::audio_region_selection_covers (framepos_t where)
4036 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4037 if ((*a)->region()->covers (where)) {
4046 Editor::prepare_for_cleanup ()
4048 cut_buffer->clear_regions ();
4049 cut_buffer->clear_playlists ();
4051 selection->clear_regions ();
4052 selection->clear_playlists ();
4054 _regions->suspend_redisplay ();
4058 Editor::finish_cleanup ()
4060 _regions->resume_redisplay ();
4064 Editor::transport_loop_location()
4067 return _session->locations()->auto_loop_location();
4074 Editor::transport_punch_location()
4077 return _session->locations()->auto_punch_location();
4084 Editor::control_layout_scroll (GdkEventScroll* ev)
4086 /* Just forward to the normal canvas scroll method. The coordinate
4087 systems are different but since the canvas is always larger than the
4088 track headers, and aligned with the trackview area, this will work.
4090 In the not too distant future this layout is going away anyway and
4091 headers will be on the canvas.
4093 return canvas_scroll_event (ev, false);
4097 Editor::session_state_saved (string)
4100 _snapshots->redisplay ();
4104 Editor::maximise_editing_space ()
4110 Gtk::Window* toplevel = current_toplevel();
4113 toplevel->fullscreen ();
4119 Editor::restore_editing_space ()
4125 Gtk::Window* toplevel = current_toplevel();
4128 toplevel->unfullscreen();
4134 * Make new playlists for a given track and also any others that belong
4135 * to the same active route group with the `select' property.
4140 Editor::new_playlists (TimeAxisView* v)
4142 begin_reversible_command (_("new playlists"));
4143 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4144 _session->playlists->get (playlists);
4145 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4146 commit_reversible_command ();
4150 * Use a copy of the current playlist for a given track and also any others that belong
4151 * to the same active route group with the `select' property.
4156 Editor::copy_playlists (TimeAxisView* v)
4158 begin_reversible_command (_("copy playlists"));
4159 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4160 _session->playlists->get (playlists);
4161 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4162 commit_reversible_command ();
4165 /** Clear the current playlist for a given track and also any others that belong
4166 * to the same active route group with the `select' property.
4171 Editor::clear_playlists (TimeAxisView* v)
4173 begin_reversible_command (_("clear playlists"));
4174 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4175 _session->playlists->get (playlists);
4176 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4177 commit_reversible_command ();
4181 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4183 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4187 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4189 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4193 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4195 atv.clear_playlist ();
4199 Editor::get_y_origin () const
4201 return vertical_adjustment.get_value ();
4204 /** Queue up a change to the viewport x origin.
4205 * @param frame New x origin.
4208 Editor::reset_x_origin (framepos_t frame)
4210 pending_visual_change.add (VisualChange::TimeOrigin);
4211 pending_visual_change.time_origin = frame;
4212 ensure_visual_change_idle_handler ();
4216 Editor::reset_y_origin (double y)
4218 pending_visual_change.add (VisualChange::YOrigin);
4219 pending_visual_change.y_origin = y;
4220 ensure_visual_change_idle_handler ();
4224 Editor::reset_zoom (framecnt_t spp)
4226 if (spp == samples_per_pixel) {
4230 pending_visual_change.add (VisualChange::ZoomLevel);
4231 pending_visual_change.samples_per_pixel = spp;
4232 ensure_visual_change_idle_handler ();
4236 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4238 reset_x_origin (frame);
4241 if (!no_save_visual) {
4242 undo_visual_stack.push_back (current_visual_state(false));
4246 Editor::VisualState::VisualState (bool with_tracks)
4247 : gui_state (with_tracks ? new GUIObjectState : 0)
4251 Editor::VisualState::~VisualState ()
4256 Editor::VisualState*
4257 Editor::current_visual_state (bool with_tracks)
4259 VisualState* vs = new VisualState (with_tracks);
4260 vs->y_position = vertical_adjustment.get_value();
4261 vs->samples_per_pixel = samples_per_pixel;
4262 vs->leftmost_frame = leftmost_frame;
4263 vs->zoom_focus = zoom_focus;
4266 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4273 Editor::undo_visual_state ()
4275 if (undo_visual_stack.empty()) {
4279 VisualState* vs = undo_visual_stack.back();
4280 undo_visual_stack.pop_back();
4283 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4286 use_visual_state (*vs);
4291 Editor::redo_visual_state ()
4293 if (redo_visual_stack.empty()) {
4297 VisualState* vs = redo_visual_stack.back();
4298 redo_visual_stack.pop_back();
4300 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4301 // why do we check here?
4302 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4305 use_visual_state (*vs);
4310 Editor::swap_visual_state ()
4312 if (undo_visual_stack.empty()) {
4313 redo_visual_state ();
4315 undo_visual_state ();
4320 Editor::use_visual_state (VisualState& vs)
4322 PBD::Unwinder<bool> nsv (no_save_visual, true);
4323 DisplaySuspender ds;
4325 vertical_adjustment.set_value (vs.y_position);
4327 set_zoom_focus (vs.zoom_focus);
4328 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4331 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4333 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4334 (*i)->clear_property_cache();
4335 (*i)->reset_visual_state ();
4339 _routes->update_visibility ();
4342 /** This is the core function that controls the zoom level of the canvas. It is called
4343 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4344 * @param spp new number of samples per pixel
4347 Editor::set_samples_per_pixel (framecnt_t spp)
4353 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4354 const framecnt_t lots_of_pixels = 4000;
4356 /* if the zoom level is greater than what you'd get trying to display 3
4357 * days of audio on a really big screen, then it's too big.
4360 if (spp * lots_of_pixels > three_days) {
4364 samples_per_pixel = spp;
4367 tempo_lines->tempo_map_changed();
4370 bool const showing_time_selection = selection->time.length() > 0;
4372 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4373 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4374 (*i)->reshow_selection (selection->time);
4378 ZoomChanged (); /* EMIT_SIGNAL */
4380 ArdourCanvas::GtkCanvasViewport* c;
4382 c = get_track_canvas();
4384 c->canvas()->zoomed ();
4387 if (playhead_cursor) {
4388 playhead_cursor->set_position (playhead_cursor->current_frame ());
4391 refresh_location_display();
4392 _summary->set_overlays_dirty ();
4394 update_marker_labels ();
4400 Editor::queue_visual_videotimeline_update ()
4403 * pending_visual_change.add (VisualChange::VideoTimeline);
4404 * or maybe even more specific: which videotimeline-image
4405 * currently it calls update_video_timeline() to update
4406 * _all outdated_ images on the video-timeline.
4407 * see 'exposeimg()' in video_image_frame.cc
4409 ensure_visual_change_idle_handler ();
4413 Editor::ensure_visual_change_idle_handler ()
4415 if (pending_visual_change.idle_handler_id < 0) {
4416 // see comment in add_to_idle_resize above.
4417 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4418 pending_visual_change.being_handled = false;
4423 Editor::_idle_visual_changer (void* arg)
4425 return static_cast<Editor*>(arg)->idle_visual_changer ();
4429 Editor::idle_visual_changer ()
4431 /* set_horizontal_position() below (and maybe other calls) call
4432 gtk_main_iteration(), so it's possible that a signal will be handled
4433 half-way through this method. If this signal wants an
4434 idle_visual_changer we must schedule another one after this one, so
4435 mark the idle_handler_id as -1 here to allow that. Also make a note
4436 that we are doing the visual change, so that changes in response to
4437 super-rapid-screen-update can be dropped if we are still processing
4441 pending_visual_change.idle_handler_id = -1;
4442 pending_visual_change.being_handled = true;
4444 VisualChange vc = pending_visual_change;
4446 pending_visual_change.pending = (VisualChange::Type) 0;
4448 visual_changer (vc);
4450 pending_visual_change.being_handled = false;
4452 return 0; /* this is always a one-shot call */
4456 Editor::visual_changer (const VisualChange& vc)
4458 double const last_time_origin = horizontal_position ();
4460 if (vc.pending & VisualChange::ZoomLevel) {
4461 set_samples_per_pixel (vc.samples_per_pixel);
4463 compute_fixed_ruler_scale ();
4465 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4466 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4468 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4469 current_bbt_points_begin, current_bbt_points_end);
4470 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4471 current_bbt_points_begin, current_bbt_points_end);
4472 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4474 update_video_timeline();
4477 if (vc.pending & VisualChange::TimeOrigin) {
4478 set_horizontal_position (vc.time_origin / samples_per_pixel);
4481 if (vc.pending & VisualChange::YOrigin) {
4482 vertical_adjustment.set_value (vc.y_origin);
4485 if (last_time_origin == horizontal_position ()) {
4486 /* changed signal not emitted */
4487 update_fixed_rulers ();
4488 redisplay_tempo (true);
4491 if (!(vc.pending & VisualChange::ZoomLevel)) {
4492 update_video_timeline();
4495 _summary->set_overlays_dirty ();
4498 struct EditorOrderTimeAxisSorter {
4499 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4500 return a->order () < b->order ();
4505 Editor::sort_track_selection (TrackViewList& sel)
4507 EditorOrderTimeAxisSorter cmp;
4512 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4515 framepos_t where = 0;
4516 EditPoint ep = _edit_point;
4518 if (Profile->get_mixbus())
4519 if (ep == EditAtSelectedMarker)
4520 ep = EditAtPlayhead;
4522 if (from_outside_canvas && (ep == EditAtMouse)) {
4523 ep = EditAtPlayhead;
4524 } else if (from_context_menu && (ep == EditAtMouse)) {
4525 return canvas_event_sample (&context_click_event, 0, 0);
4528 if (entered_marker) {
4529 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4530 return entered_marker->position();
4533 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4534 ep = EditAtSelectedMarker;
4537 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4538 ep = EditAtPlayhead;
4542 case EditAtPlayhead:
4543 if (_dragging_playhead) {
4544 where = *_control_scroll_target;
4546 where = _session->audible_frame();
4548 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4551 case EditAtSelectedMarker:
4552 if (!selection->markers.empty()) {
4554 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4557 where = loc->start();
4561 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4569 if (!mouse_frame (where, ignored)) {
4570 /* XXX not right but what can we do ? */
4574 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4582 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4584 if (!_session) return;
4586 begin_reversible_command (cmd);
4590 if ((tll = transport_loop_location()) == 0) {
4591 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4592 XMLNode &before = _session->locations()->get_state();
4593 _session->locations()->add (loc, true);
4594 _session->set_auto_loop_location (loc);
4595 XMLNode &after = _session->locations()->get_state();
4596 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4598 XMLNode &before = tll->get_state();
4599 tll->set_hidden (false, this);
4600 tll->set (start, end);
4601 XMLNode &after = tll->get_state();
4602 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4605 commit_reversible_command ();
4609 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4611 if (!_session) return;
4613 begin_reversible_command (cmd);
4617 if ((tpl = transport_punch_location()) == 0) {
4618 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4619 XMLNode &before = _session->locations()->get_state();
4620 _session->locations()->add (loc, true);
4621 _session->set_auto_punch_location (loc);
4622 XMLNode &after = _session->locations()->get_state();
4623 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4625 XMLNode &before = tpl->get_state();
4626 tpl->set_hidden (false, this);
4627 tpl->set (start, end);
4628 XMLNode &after = tpl->get_state();
4629 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4632 commit_reversible_command ();
4635 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4636 * @param rs List to which found regions are added.
4637 * @param where Time to look at.
4638 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4641 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4643 const TrackViewList* tracks;
4646 tracks = &track_views;
4651 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4653 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4656 boost::shared_ptr<Track> tr;
4657 boost::shared_ptr<Playlist> pl;
4659 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4661 boost::shared_ptr<RegionList> regions = pl->regions_at (
4662 (framepos_t) floor ( (double) where * tr->speed()));
4664 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4665 RegionView* rv = rtv->view()->find_view (*i);
4676 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4678 const TrackViewList* tracks;
4681 tracks = &track_views;
4686 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4687 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4689 boost::shared_ptr<Track> tr;
4690 boost::shared_ptr<Playlist> pl;
4692 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4694 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4695 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4697 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4699 RegionView* rv = rtv->view()->find_view (*i);
4710 /** Get regions using the following method:
4712 * Make a region list using:
4713 * (a) any selected regions
4714 * (b) the intersection of any selected tracks and the edit point(*)
4715 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4717 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4719 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4723 Editor::get_regions_from_selection_and_edit_point ()
4725 RegionSelection regions;
4727 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4728 regions.add (entered_regionview);
4730 regions = selection->regions;
4733 if ( regions.empty() ) {
4734 TrackViewList tracks = selection->tracks;
4736 if (!tracks.empty()) {
4737 /* no region selected or entered, but some selected tracks:
4738 * act on all regions on the selected tracks at the edit point
4740 framepos_t const where = get_preferred_edit_position ();
4741 get_regions_at(regions, where, tracks);
4748 /** Get regions using the following method:
4750 * Make a region list using:
4751 * (a) any selected regions
4752 * (b) the intersection of any selected tracks and the edit point(*)
4753 * (c) if neither exists, then whatever region is under the mouse
4755 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4757 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4760 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4762 RegionSelection regions;
4764 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4765 regions.add (entered_regionview);
4767 regions = selection->regions;
4770 if ( regions.empty() ) {
4771 TrackViewList tracks = selection->tracks;
4773 if (!tracks.empty()) {
4774 /* no region selected or entered, but some selected tracks:
4775 * act on all regions on the selected tracks at the edit point
4777 get_regions_at(regions, pos, tracks);
4784 /** Start with regions that are selected, or the entered regionview if none are selected.
4785 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4786 * of the regions that we started with.
4790 Editor::get_regions_from_selection_and_entered ()
4792 RegionSelection regions = selection->regions;
4794 if (regions.empty() && entered_regionview) {
4795 regions.add (entered_regionview);
4802 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4804 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4805 RouteTimeAxisView* rtav;
4807 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4808 boost::shared_ptr<Playlist> pl;
4809 std::vector<boost::shared_ptr<Region> > results;
4810 boost::shared_ptr<Track> tr;
4812 if ((tr = rtav->track()) == 0) {
4817 if ((pl = (tr->playlist())) != 0) {
4818 boost::shared_ptr<Region> r = pl->region_by_id (id);
4820 RegionView* rv = rtav->view()->find_view (r);
4822 regions.push_back (rv);
4831 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4834 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4835 MidiTimeAxisView* mtav;
4837 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4839 mtav->get_per_region_note_selection (selection);
4846 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4848 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4850 RouteTimeAxisView* tatv;
4852 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4854 boost::shared_ptr<Playlist> pl;
4855 vector<boost::shared_ptr<Region> > results;
4857 boost::shared_ptr<Track> tr;
4859 if ((tr = tatv->track()) == 0) {
4864 if ((pl = (tr->playlist())) != 0) {
4865 if (src_comparison) {
4866 pl->get_source_equivalent_regions (region, results);
4868 pl->get_region_list_equivalent_regions (region, results);
4872 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4873 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4874 regions.push_back (marv);
4883 Editor::show_rhythm_ferret ()
4885 if (rhythm_ferret == 0) {
4886 rhythm_ferret = new RhythmFerret(*this);
4889 rhythm_ferret->set_session (_session);
4890 rhythm_ferret->show ();
4891 rhythm_ferret->present ();
4895 Editor::first_idle ()
4897 MessageDialog* dialog = 0;
4899 if (track_views.size() > 1) {
4900 Timers::TimerSuspender t;
4901 dialog = new MessageDialog (
4902 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4906 ARDOUR_UI::instance()->flush_pending ();
4909 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4913 // first idle adds route children (automation tracks), so we need to redisplay here
4914 _routes->redisplay ();
4918 if (_session->undo_depth() == 0) {
4919 undo_action->set_sensitive(false);
4921 redo_action->set_sensitive(false);
4922 begin_selection_op_history ();
4928 Editor::_idle_resize (gpointer arg)
4930 return ((Editor*)arg)->idle_resize ();
4934 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4936 if (resize_idle_id < 0) {
4937 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
4938 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
4939 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
4941 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
4942 _pending_resize_amount = 0;
4945 /* make a note of the smallest resulting height, so that we can clamp the
4946 lower limit at TimeAxisView::hSmall */
4948 int32_t min_resulting = INT32_MAX;
4950 _pending_resize_amount += h;
4951 _pending_resize_view = view;
4953 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4955 if (selection->tracks.contains (_pending_resize_view)) {
4956 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4957 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4961 if (min_resulting < 0) {
4966 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4967 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4971 /** Handle pending resizing of tracks */
4973 Editor::idle_resize ()
4975 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4977 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4978 selection->tracks.contains (_pending_resize_view)) {
4980 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4981 if (*i != _pending_resize_view) {
4982 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4987 _pending_resize_amount = 0;
4988 _group_tabs->set_dirty ();
4989 resize_idle_id = -1;
4997 ENSURE_GUI_THREAD (*this, &Editor::located);
5000 playhead_cursor->set_position (_session->audible_frame ());
5001 if (_follow_playhead && !_pending_initial_locate) {
5002 reset_x_origin_to_follow_playhead ();
5006 _pending_locate_request = false;
5007 _pending_initial_locate = false;
5011 Editor::region_view_added (RegionView * rv)
5013 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5014 if (rv->region ()->id () == (*pr)) {
5015 selection->add (rv);
5016 selection->regions.pending.erase (pr);
5021 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5023 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5024 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5025 if (rv->region()->id () == (*rnote).first) {
5026 mrv->select_notes ((*rnote).second);
5027 selection->pending_midi_note_selection.erase(rnote);
5033 _summary->set_background_dirty ();
5037 Editor::region_view_removed ()
5039 _summary->set_background_dirty ();
5043 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5045 TrackViewList::const_iterator j = track_views.begin ();
5046 while (j != track_views.end()) {
5047 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5048 if (rtv && rtv->route() == r) {
5059 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5063 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5064 TimeAxisView* tv = axis_view_from_route (*i);
5074 Editor::suspend_route_redisplay ()
5077 _routes->suspend_redisplay();
5082 Editor::resume_route_redisplay ()
5085 _routes->redisplay(); // queue redisplay
5086 _routes->resume_redisplay();
5091 Editor::add_routes (RouteList& routes)
5093 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5095 RouteTimeAxisView *rtv;
5096 list<RouteTimeAxisView*> new_views;
5097 TrackViewList new_selection;
5098 bool from_scratch = (track_views.size() == 0);
5100 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5101 boost::shared_ptr<Route> route = (*x);
5103 if (route->is_auditioner() || route->is_monitor()) {
5107 DataType dt = route->input()->default_type();
5109 if (dt == ARDOUR::DataType::AUDIO) {
5110 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5111 rtv->set_route (route);
5112 } else if (dt == ARDOUR::DataType::MIDI) {
5113 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5114 rtv->set_route (route);
5116 throw unknown_type();
5119 new_views.push_back (rtv);
5120 track_views.push_back (rtv);
5121 new_selection.push_back (rtv);
5123 rtv->effective_gain_display ();
5125 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5126 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5129 if (new_views.size() > 0) {
5130 _routes->routes_added (new_views);
5131 _summary->routes_added (new_views);
5134 if (!from_scratch) {
5135 selection->tracks.clear();
5136 selection->add (new_selection);
5137 begin_selection_op_history();
5140 if (show_editor_mixer_when_tracks_arrive) {
5141 show_editor_mixer (true);
5144 editor_list_button.set_sensitive (true);
5148 Editor::timeaxisview_deleted (TimeAxisView *tv)
5150 if (tv == entered_track) {
5154 if (_session && _session->deletion_in_progress()) {
5155 /* the situation is under control */
5159 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5161 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5163 _routes->route_removed (tv);
5165 TimeAxisView::Children c = tv->get_child_list ();
5166 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5167 if (entered_track == i->get()) {
5172 /* remove it from the list of track views */
5174 TrackViewList::iterator i;
5176 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5177 i = track_views.erase (i);
5180 /* update whatever the current mixer strip is displaying, if revelant */
5182 boost::shared_ptr<Route> route;
5185 route = rtav->route ();
5188 if (current_mixer_strip && current_mixer_strip->route() == route) {
5190 TimeAxisView* next_tv;
5192 if (track_views.empty()) {
5194 } else if (i == track_views.end()) {
5195 next_tv = track_views.front();
5202 set_selected_mixer_strip (*next_tv);
5204 /* make the editor mixer strip go away setting the
5205 * button to inactive (which also unticks the menu option)
5208 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5214 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5216 if (apply_to_selection) {
5217 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5219 TrackSelection::iterator j = i;
5222 hide_track_in_display (*i, false);
5227 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5229 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5230 // this will hide the mixer strip
5231 set_selected_mixer_strip (*tv);
5234 _routes->hide_track_in_display (*tv);
5239 Editor::sync_track_view_list_and_routes ()
5241 track_views = TrackViewList (_routes->views ());
5243 _summary->set_background_dirty();
5244 _group_tabs->set_dirty ();
5246 return false; // do not call again (until needed)
5250 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5252 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5257 /** Find a RouteTimeAxisView by the ID of its route */
5259 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5261 RouteTimeAxisView* v;
5263 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5264 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5265 if(v->route()->id() == id) {
5275 Editor::fit_route_group (RouteGroup *g)
5277 TrackViewList ts = axis_views_from_routes (g->route_list ());
5282 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5284 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5287 _session->cancel_audition ();
5291 if (_session->is_auditioning()) {
5292 _session->cancel_audition ();
5293 if (r == last_audition_region) {
5298 _session->audition_region (r);
5299 last_audition_region = r;
5304 Editor::hide_a_region (boost::shared_ptr<Region> r)
5306 r->set_hidden (true);
5310 Editor::show_a_region (boost::shared_ptr<Region> r)
5312 r->set_hidden (false);
5316 Editor::audition_region_from_region_list ()
5318 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5322 Editor::hide_region_from_region_list ()
5324 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5328 Editor::show_region_in_region_list ()
5330 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5334 Editor::step_edit_status_change (bool yn)
5337 start_step_editing ();
5339 stop_step_editing ();
5344 Editor::start_step_editing ()
5346 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5350 Editor::stop_step_editing ()
5352 step_edit_connection.disconnect ();
5356 Editor::check_step_edit ()
5358 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5359 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5361 mtv->check_step_edit ();
5365 return true; // do it again, till we stop
5369 Editor::scroll_press (Direction dir)
5371 ++_scroll_callbacks;
5373 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5374 /* delay the first auto-repeat */
5380 scroll_backward (1);
5388 scroll_up_one_track ();
5392 scroll_down_one_track ();
5396 /* do hacky auto-repeat */
5397 if (!_scroll_connection.connected ()) {
5399 _scroll_connection = Glib::signal_timeout().connect (
5400 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5403 _scroll_callbacks = 0;
5410 Editor::scroll_release ()
5412 _scroll_connection.disconnect ();
5415 /** Queue a change for the Editor viewport x origin to follow the playhead */
5417 Editor::reset_x_origin_to_follow_playhead ()
5419 framepos_t const frame = playhead_cursor->current_frame ();
5421 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5423 if (_session->transport_speed() < 0) {
5425 if (frame > (current_page_samples() / 2)) {
5426 center_screen (frame-(current_page_samples()/2));
5428 center_screen (current_page_samples()/2);
5435 if (frame < leftmost_frame) {
5437 if (_session->transport_rolling()) {
5438 /* rolling; end up with the playhead at the right of the page */
5439 l = frame - current_page_samples ();
5441 /* not rolling: end up with the playhead 1/4 of the way along the page */
5442 l = frame - current_page_samples() / 4;
5446 if (_session->transport_rolling()) {
5447 /* rolling: end up with the playhead on the left of the page */
5450 /* not rolling: end up with the playhead 3/4 of the way along the page */
5451 l = frame - 3 * current_page_samples() / 4;
5459 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5465 Editor::super_rapid_screen_update ()
5467 if (!_session || !_session->engine().running()) {
5471 /* METERING / MIXER STRIPS */
5473 /* update track meters, if required */
5474 if (contents().is_mapped() && meters_running) {
5475 RouteTimeAxisView* rtv;
5476 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5477 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5478 rtv->fast_update ();
5483 /* and any current mixer strip */
5484 if (current_mixer_strip) {
5485 current_mixer_strip->fast_update ();
5488 /* PLAYHEAD AND VIEWPORT */
5490 framepos_t const frame = _session->audible_frame();
5492 /* There are a few reasons why we might not update the playhead / viewport stuff:
5494 * 1. we don't update things when there's a pending locate request, otherwise
5495 * when the editor requests a locate there is a chance that this method
5496 * will move the playhead before the locate request is processed, causing
5498 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5499 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5502 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5504 last_update_frame = frame;
5506 if (!_dragging_playhead) {
5507 playhead_cursor->set_position (frame);
5510 if (!_stationary_playhead) {
5512 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5513 /* We only do this if we aren't already
5514 handling a visual change (ie if
5515 pending_visual_change.being_handled is
5516 false) so that these requests don't stack
5517 up there are too many of them to handle in
5520 reset_x_origin_to_follow_playhead ();
5525 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5526 framepos_t const frame = playhead_cursor->current_frame ();
5527 double target = ((double)frame - (double)current_page_samples()/2.0);
5528 if (target <= 0.0) {
5531 // compare to EditorCursor::set_position()
5532 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5533 double const new_pos = sample_to_pixel_unrounded (target);
5534 if (rint (new_pos) != rint (old_pos)) {
5535 reset_x_origin (pixel_to_sample (floor (new_pos)));
5546 Editor::session_going_away ()
5548 _have_idled = false;
5550 _session_connections.drop_connections ();
5552 super_rapid_screen_update_connection.disconnect ();
5554 selection->clear ();
5555 cut_buffer->clear ();
5557 clicked_regionview = 0;
5558 clicked_axisview = 0;
5559 clicked_routeview = 0;
5560 entered_regionview = 0;
5562 last_update_frame = 0;
5565 playhead_cursor->hide ();
5567 /* rip everything out of the list displays */
5571 _route_groups->clear ();
5573 /* do this first so that deleting a track doesn't reset cms to null
5574 and thus cause a leak.
5577 if (current_mixer_strip) {
5578 if (current_mixer_strip->get_parent() != 0) {
5579 global_hpacker.remove (*current_mixer_strip);
5581 delete current_mixer_strip;
5582 current_mixer_strip = 0;
5585 /* delete all trackviews */
5587 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5590 track_views.clear ();
5592 nudge_clock->set_session (0);
5594 editor_list_button.set_active(false);
5595 editor_list_button.set_sensitive(false);
5597 /* clear tempo/meter rulers */
5598 remove_metric_marks ();
5600 clear_marker_display ();
5602 stop_step_editing ();
5606 /* get rid of any existing editor mixer strip */
5608 WindowTitle title(Glib::get_application_name());
5609 title += _("Editor");
5611 own_window()->set_title (title.get_string());
5614 SessionHandlePtr::session_going_away ();
5619 Editor::show_editor_list (bool yn)
5622 _the_notebook.show ();
5624 _the_notebook.hide ();
5629 Editor::change_region_layering_order (bool from_context_menu)
5631 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5633 if (!clicked_routeview) {
5634 if (layering_order_editor) {
5635 layering_order_editor->hide ();
5640 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5646 boost::shared_ptr<Playlist> pl = track->playlist();
5652 if (layering_order_editor == 0) {
5653 layering_order_editor = new RegionLayeringOrderEditor (*this);
5656 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5657 layering_order_editor->maybe_present ();
5661 Editor::update_region_layering_order_editor ()
5663 if (layering_order_editor && layering_order_editor->is_visible ()) {
5664 change_region_layering_order (true);
5669 Editor::setup_fade_images ()
5671 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5672 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5673 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5674 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5675 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5677 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5678 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5679 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5680 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5681 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5683 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5684 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5685 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5686 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5687 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5689 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5690 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5691 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5692 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5693 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5697 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5699 Editor::action_menu_item (std::string const & name)
5701 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5704 return *manage (a->create_menu_item ());
5708 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5710 EventBox* b = manage (new EventBox);
5711 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5712 Label* l = manage (new Label (name));
5716 _the_notebook.append_page (widget, *b);
5720 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5722 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5723 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5726 if (ev->type == GDK_2BUTTON_PRESS) {
5728 /* double-click on a notebook tab shrinks or expands the notebook */
5730 if (_notebook_shrunk) {
5731 if (pre_notebook_shrink_pane_width) {
5732 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5734 _notebook_shrunk = false;
5736 pre_notebook_shrink_pane_width = edit_pane.get_position();
5738 /* this expands the LHS of the edit pane to cover the notebook
5739 PAGE but leaves the tabs visible.
5741 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5742 _notebook_shrunk = true;
5750 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5752 using namespace Menu_Helpers;
5754 MenuList& items = _control_point_context_menu.items ();
5757 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5758 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5759 if (!can_remove_control_point (item)) {
5760 items.back().set_sensitive (false);
5763 _control_point_context_menu.popup (event->button.button, event->button.time);
5767 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5769 using namespace Menu_Helpers;
5771 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5776 /* We need to get the selection here and pass it to the operations, since
5777 popping up the menu will cause a region leave event which clears
5778 entered_regionview. */
5780 MidiRegionView& mrv = note->region_view();
5781 const RegionSelection rs = get_regions_from_selection_and_entered ();
5782 const uint32_t sel_size = mrv.selection_size ();
5784 MenuList& items = _note_context_menu.items();
5788 items.push_back(MenuElem(_("Delete"),
5789 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5792 items.push_back(MenuElem(_("Edit..."),
5793 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5794 if (sel_size != 1) {
5795 items.back().set_sensitive (false);
5798 items.push_back(MenuElem(_("Transpose..."),
5799 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
5802 items.push_back(MenuElem(_("Legatize"),
5803 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5805 items.back().set_sensitive (false);
5808 items.push_back(MenuElem(_("Quantize..."),
5809 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5811 items.push_back(MenuElem(_("Remove Overlap"),
5812 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5814 items.back().set_sensitive (false);
5817 items.push_back(MenuElem(_("Transform..."),
5818 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5820 _note_context_menu.popup (event->button.button, event->button.time);
5824 Editor::zoom_vertical_modifier_released()
5826 _stepping_axis_view = 0;
5830 Editor::ui_parameter_changed (string parameter)
5832 if (parameter == "icon-set") {
5833 while (!_cursor_stack.empty()) {
5834 _cursor_stack.pop_back();
5836 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
5837 _cursor_stack.push_back(_cursors->grabber);
5838 } else if (parameter == "draggable-playhead") {
5839 if (_verbose_cursor) {
5840 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
5846 Editor::use_own_window (bool and_fill_it)
5848 bool new_window = !own_window();
5850 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
5852 if (win && new_window) {
5853 win->set_name ("EditorWindow");
5855 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
5857 // win->signal_realize().connect (*this, &Editor::on_realize);
5858 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
5859 win->set_data ("ardour-bindings", bindings);
5864 DisplaySuspender ds;
5865 contents().show_all ();
5867 /* XXX: this is a bit unfortunate; it would probably
5868 be nicer if we could just call show () above rather
5869 than needing the show_all ()
5872 /* re-hide stuff if necessary */
5873 editor_list_button_toggled ();
5874 parameter_changed ("show-summary");
5875 parameter_changed ("show-group-tabs");
5876 parameter_changed ("show-zoom-tools");
5878 /* now reset all audio_time_axis heights, because widgets might need
5884 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5885 tv = (static_cast<TimeAxisView*>(*i));
5886 tv->reset_height ();
5889 if (current_mixer_strip) {
5890 current_mixer_strip->hide_things ();
5891 current_mixer_strip->parameter_changed ("mixer-element-visibility");