2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include "gtkmm2ext/utils.h"
63 #include "gtkmm2ext/window_title.h"
64 #include "gtkmm2ext/choice.h"
65 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
67 #include "ardour/audio_track.h"
68 #include "ardour/audioengine.h"
69 #include "ardour/audioregion.h"
70 #include "ardour/lmath.h"
71 #include "ardour/location.h"
72 #include "ardour/profile.h"
73 #include "ardour/route_group.h"
74 #include "ardour/session_playlists.h"
75 #include "ardour/tempo.h"
76 #include "ardour/utils.h"
78 #include "canvas/debug.h"
79 #include "canvas/text.h"
81 #include "control_protocol/control_protocol.h"
84 #include "analysis_window.h"
85 #include "audio_clock.h"
86 #include "audio_region_view.h"
87 #include "audio_streamview.h"
88 #include "audio_time_axis.h"
89 #include "automation_time_axis.h"
90 #include "bundle_manager.h"
91 #include "crossfade_edit.h"
95 #include "editor_cursors.h"
96 #include "editor_drag.h"
97 #include "editor_group_tabs.h"
98 #include "editor_locations.h"
99 #include "editor_regions.h"
100 #include "editor_route_groups.h"
101 #include "editor_routes.h"
102 #include "editor_snapshots.h"
103 #include "editor_summary.h"
104 #include "global_port_matrix.h"
105 #include "gui_object.h"
106 #include "gui_thread.h"
107 #include "keyboard.h"
109 #include "midi_region_view.h"
110 #include "midi_time_axis.h"
111 #include "mixer_strip.h"
112 #include "mixer_ui.h"
113 #include "mouse_cursors.h"
114 #include "note_base.h"
115 #include "playlist_selector.h"
116 #include "public_editor.h"
117 #include "quantize_dialog.h"
118 #include "region_layering_order_editor.h"
119 #include "rgb_macros.h"
120 #include "rhythm_ferret.h"
121 #include "selection.h"
123 #include "tempo_lines.h"
124 #include "time_axis_view.h"
126 #include "tooltips.h"
127 #include "ui_config.h"
129 #include "verbose_cursor.h"
134 using namespace ARDOUR;
135 using namespace ARDOUR_UI_UTILS;
138 using namespace Glib;
139 using namespace Gtkmm2ext;
140 using namespace Editing;
142 using PBD::internationalize;
144 using Gtkmm2ext::Keyboard;
146 double Editor::timebar_height = 15.0;
148 static const gchar *_snap_type_strings[] = {
182 static const gchar *_snap_mode_strings[] = {
189 static const gchar *_edit_point_strings[] = {
196 static const gchar *_edit_mode_strings[] = {
204 static const gchar *_zoom_focus_strings[] = {
214 #ifdef USE_RUBBERBAND
215 static const gchar *_rb_opt_strings[] = {
218 N_("Balanced multitimbral mixture"),
219 N_("Unpitched percussion with stable notes"),
220 N_("Crisp monophonic instrumental"),
221 N_("Unpitched solo percussion"),
222 N_("Resample without preserving pitch"),
227 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
230 pane_size_watcher (Paned* pane)
232 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
236 Quartz: impossible to access
238 so stop that by preventing it from ever getting too narrow. 35
239 pixels is basically a rough guess at the tab width.
244 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
246 gint pos = pane->get_position ();
248 if (pos > max_width_of_lhs) {
249 pane->set_position (max_width_of_lhs);
254 : PublicEditor (global_hpacker)
255 , editor_mixer_strip_width (Wide)
256 , constructed (false)
257 , _playlist_selector (0)
258 , no_save_visual (false)
260 , samples_per_pixel (2048)
261 , zoom_focus (ZoomFocusPlayhead)
262 , mouse_mode (MouseObject)
263 , pre_internal_snap_type (SnapToBeat)
264 , pre_internal_snap_mode (SnapOff)
265 , internal_snap_type (SnapToBeat)
266 , internal_snap_mode (SnapOff)
267 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
268 , _notebook_shrunk (false)
269 , location_marker_color (0)
270 , location_range_color (0)
271 , location_loop_color (0)
272 , location_punch_color (0)
273 , location_cd_marker_color (0)
275 , _show_marker_lines (false)
276 , clicked_axisview (0)
277 , clicked_routeview (0)
278 , clicked_regionview (0)
279 , clicked_selection (0)
280 , clicked_control_point (0)
281 , button_release_can_deselect (true)
282 , _mouse_changed_selection (false)
283 , region_edit_menu_split_item (0)
284 , region_edit_menu_split_multichannel_item (0)
285 , track_region_edit_playlist_menu (0)
286 , track_edit_playlist_submenu (0)
287 , track_selection_edit_playlist_submenu (0)
288 , _popup_region_menu_item (0)
290 , _track_canvas_viewport (0)
291 , within_track_canvas (false)
292 , _verbose_cursor (0)
297 , range_marker_group (0)
298 , transport_marker_group (0)
299 , cd_marker_group (0)
300 , _time_markers_group (0)
301 , hv_scroll_group (0)
303 , cursor_scroll_group (0)
304 , no_scroll_group (0)
305 , _trackview_group (0)
306 , _drag_motion_group (0)
307 , _canvas_drop_zone (0)
308 , no_ruler_shown_update (false)
309 , ruler_grabbed_widget (0)
311 , minsec_mark_interval (0)
312 , minsec_mark_modulo (0)
314 , timecode_mark_modulo (0)
315 , timecode_nmarks (0)
316 , _samples_ruler_interval (0)
319 , bbt_bar_helper_on (0)
320 , bbt_accent_modulo (0)
325 , visible_timebars (0)
326 , editor_ruler_menu (0)
330 , range_marker_bar (0)
331 , transport_marker_bar (0)
333 , minsec_label (_("Mins:Secs"))
334 , bbt_label (_("Bars:Beats"))
335 , timecode_label (_("Timecode"))
336 , samples_label (_("Samples"))
337 , tempo_label (_("Tempo"))
338 , meter_label (_("Meter"))
339 , mark_label (_("Location Markers"))
340 , range_mark_label (_("Range Markers"))
341 , transport_mark_label (_("Loop/Punch Ranges"))
342 , cd_mark_label (_("CD Markers"))
343 , videotl_label (_("Video Timeline"))
345 , playhead_cursor (0)
346 , edit_packer (4, 4, true)
347 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
348 , horizontal_adjustment (0.0, 0.0, 1e16)
349 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
350 , controls_layout (unused_adjustment, vertical_adjustment)
351 , _scroll_callbacks (0)
352 , _visible_canvas_width (0)
353 , _visible_canvas_height (0)
354 , _full_canvas_height (0)
355 , edit_controls_left_menu (0)
356 , edit_controls_right_menu (0)
357 , last_update_frame (0)
358 , cut_buffer_start (0)
359 , cut_buffer_length (0)
360 , button_bindings (0)
364 , current_interthread_info (0)
365 , analysis_window (0)
366 , select_new_marker (false)
368 , scrubbing_direction (0)
369 , scrub_reversals (0)
370 , scrub_reverse_distance (0)
371 , have_pending_keyboard_selection (false)
372 , pending_keyboard_selection_start (0)
373 , _snap_type (SnapToBeat)
374 , _snap_mode (SnapOff)
375 , snap_threshold (5.0)
376 , ignore_gui_changes (false)
377 , _drags (new DragManager (this))
379 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
380 , _dragging_playhead (false)
381 , _dragging_edit_point (false)
382 , _show_measures (true)
383 , _follow_playhead (true)
384 , _stationary_playhead (false)
387 , global_rect_group (0)
388 , time_line_group (0)
389 , tempo_or_meter_marker_menu (0)
391 , range_marker_menu (0)
392 , transport_marker_menu (0)
393 , new_transport_marker_menu (0)
395 , marker_menu_item (0)
396 , bbt_beat_subdivision (4)
397 , _visible_track_count (-1)
398 , toolbar_selection_clock_table (2,3)
399 , automation_mode_button (_("mode"))
400 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
401 , selection (new Selection (this))
402 , cut_buffer (new Selection (this))
403 , _selection_memento (new SelectionMemento())
404 , _all_region_actions_sensitized (false)
405 , _ignore_region_action (false)
406 , _last_region_menu_was_main (false)
407 , _ignore_follow_edits (false)
408 , cd_marker_bar_drag_rect (0)
409 , range_bar_drag_rect (0)
410 , transport_bar_drag_rect (0)
411 , transport_bar_range_rect (0)
412 , transport_bar_preroll_rect (0)
413 , transport_bar_postroll_rect (0)
414 , transport_loop_range_rect (0)
415 , transport_punch_range_rect (0)
416 , transport_punchin_line (0)
417 , transport_punchout_line (0)
418 , transport_preroll_rect (0)
419 , transport_postroll_rect (0)
421 , rubberband_rect (0)
427 , autoscroll_horizontal_allowed (false)
428 , autoscroll_vertical_allowed (false)
430 , autoscroll_widget (0)
431 , show_gain_after_trim (false)
432 , selection_op_cmd_depth (0)
433 , selection_op_history_it (0)
435 , current_mixer_strip (0)
436 , show_editor_mixer_when_tracks_arrive (false)
437 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
438 , current_stepping_trackview (0)
439 , last_track_height_step_timestamp (0)
441 , entered_regionview (0)
442 , clear_entered_track (false)
443 , _edit_point (EditAtMouse)
444 , meters_running (false)
446 , _have_idled (false)
447 , resize_idle_id (-1)
448 , _pending_resize_amount (0)
449 , _pending_resize_view (0)
450 , _pending_locate_request (false)
451 , _pending_initial_locate (false)
455 , layering_order_editor (0)
456 , _last_cut_copy_source_track (0)
457 , _region_selection_change_updates_region_list (true)
459 , _following_mixer_selection (false)
460 , _control_point_toggled_on_press (false)
461 , _stepping_axis_view (0)
462 , quantize_dialog (0)
463 , _main_menu_disabler (0)
465 /* we are a singleton */
467 PublicEditor::_instance = this;
471 last_event_time.tv_sec = 0;
472 last_event_time.tv_usec = 0;
474 global_hpacker.set_data ("ardour-bindings", &key_bindings);
476 selection_op_history.clear();
479 snap_type_strings = I18N (_snap_type_strings);
480 snap_mode_strings = I18N (_snap_mode_strings);
481 zoom_focus_strings = I18N (_zoom_focus_strings);
482 edit_mode_strings = I18N (_edit_mode_strings);
483 edit_point_strings = I18N (_edit_point_strings);
484 #ifdef USE_RUBBERBAND
485 rb_opt_strings = I18N (_rb_opt_strings);
489 build_edit_mode_menu();
490 build_zoom_focus_menu();
491 build_track_count_menu();
492 build_snap_mode_menu();
493 build_snap_type_menu();
494 build_edit_point_menu();
496 location_marker_color = ARDOUR_UI::config()->color ("location marker");
497 location_range_color = ARDOUR_UI::config()->color ("location range");
498 location_cd_marker_color = ARDOUR_UI::config()->color ("location cd marker");
499 location_loop_color = ARDOUR_UI::config()->color ("location loop");
500 location_punch_color = ARDOUR_UI::config()->color ("location punch");
502 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
504 TimeAxisView::setup_sizes ();
505 ArdourMarker::setup_sizes (timebar_height);
507 bbt_label.set_name ("EditorRulerLabel");
508 bbt_label.set_size_request (-1, (int)timebar_height);
509 bbt_label.set_alignment (1.0, 0.5);
510 bbt_label.set_padding (5,0);
512 bbt_label.set_no_show_all();
513 minsec_label.set_name ("EditorRulerLabel");
514 minsec_label.set_size_request (-1, (int)timebar_height);
515 minsec_label.set_alignment (1.0, 0.5);
516 minsec_label.set_padding (5,0);
517 minsec_label.hide ();
518 minsec_label.set_no_show_all();
519 timecode_label.set_name ("EditorRulerLabel");
520 timecode_label.set_size_request (-1, (int)timebar_height);
521 timecode_label.set_alignment (1.0, 0.5);
522 timecode_label.set_padding (5,0);
523 timecode_label.hide ();
524 timecode_label.set_no_show_all();
525 samples_label.set_name ("EditorRulerLabel");
526 samples_label.set_size_request (-1, (int)timebar_height);
527 samples_label.set_alignment (1.0, 0.5);
528 samples_label.set_padding (5,0);
529 samples_label.hide ();
530 samples_label.set_no_show_all();
532 tempo_label.set_name ("EditorRulerLabel");
533 tempo_label.set_size_request (-1, (int)timebar_height);
534 tempo_label.set_alignment (1.0, 0.5);
535 tempo_label.set_padding (5,0);
537 tempo_label.set_no_show_all();
539 meter_label.set_name ("EditorRulerLabel");
540 meter_label.set_size_request (-1, (int)timebar_height);
541 meter_label.set_alignment (1.0, 0.5);
542 meter_label.set_padding (5,0);
544 meter_label.set_no_show_all();
546 if (Profile->get_trx()) {
547 mark_label.set_text (_("Markers"));
549 mark_label.set_name ("EditorRulerLabel");
550 mark_label.set_size_request (-1, (int)timebar_height);
551 mark_label.set_alignment (1.0, 0.5);
552 mark_label.set_padding (5,0);
554 mark_label.set_no_show_all();
556 cd_mark_label.set_name ("EditorRulerLabel");
557 cd_mark_label.set_size_request (-1, (int)timebar_height);
558 cd_mark_label.set_alignment (1.0, 0.5);
559 cd_mark_label.set_padding (5,0);
560 cd_mark_label.hide();
561 cd_mark_label.set_no_show_all();
563 videotl_bar_height = 4;
564 videotl_label.set_name ("EditorRulerLabel");
565 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
566 videotl_label.set_alignment (1.0, 0.5);
567 videotl_label.set_padding (5,0);
568 videotl_label.hide();
569 videotl_label.set_no_show_all();
571 range_mark_label.set_name ("EditorRulerLabel");
572 range_mark_label.set_size_request (-1, (int)timebar_height);
573 range_mark_label.set_alignment (1.0, 0.5);
574 range_mark_label.set_padding (5,0);
575 range_mark_label.hide();
576 range_mark_label.set_no_show_all();
578 transport_mark_label.set_name ("EditorRulerLabel");
579 transport_mark_label.set_size_request (-1, (int)timebar_height);
580 transport_mark_label.set_alignment (1.0, 0.5);
581 transport_mark_label.set_padding (5,0);
582 transport_mark_label.hide();
583 transport_mark_label.set_no_show_all();
585 initialize_canvas ();
587 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
589 _summary = new EditorSummary (this);
591 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
592 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
594 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
596 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
597 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
599 edit_controls_vbox.set_spacing (0);
600 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
601 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
603 HBox* h = manage (new HBox);
604 _group_tabs = new EditorGroupTabs (this);
605 if (!ARDOUR::Profile->get_trx()) {
606 h->pack_start (*_group_tabs, PACK_SHRINK);
608 h->pack_start (edit_controls_vbox);
609 controls_layout.add (*h);
611 controls_layout.set_name ("EditControlsBase");
612 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
613 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
614 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
616 _cursors = new MouseCursors;
617 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
618 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
620 /* Push default cursor to ever-present bottom of cursor stack. */
621 push_canvas_cursor(_cursors->grabber);
623 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
625 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
626 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
627 pad_line_1->set_outline_color (0xFF0000FF);
633 edit_packer.set_col_spacings (0);
634 edit_packer.set_row_spacings (0);
635 edit_packer.set_homogeneous (false);
636 edit_packer.set_border_width (0);
637 edit_packer.set_name ("EditorWindow");
639 time_bars_event_box.add (time_bars_vbox);
640 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
641 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
643 /* labels for the time bars */
644 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
646 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
648 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
650 bottom_hbox.set_border_width (2);
651 bottom_hbox.set_spacing (3);
653 _route_groups = new EditorRouteGroups (this);
654 _routes = new EditorRoutes (this);
655 _regions = new EditorRegions (this);
656 _snapshots = new EditorSnapshots (this);
657 _locations = new EditorLocations (this);
659 /* these are static location signals */
661 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
662 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
663 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
665 add_notebook_page (_("Regions"), _regions->widget ());
666 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
667 add_notebook_page (_("Snapshots"), _snapshots->widget ());
668 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
669 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
671 _the_notebook.set_show_tabs (true);
672 _the_notebook.set_scrollable (true);
673 _the_notebook.popup_disable ();
674 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
675 _the_notebook.show_all ();
677 _notebook_shrunk = false;
679 editor_summary_pane.pack1(edit_packer);
681 Button* summary_arrows_left_left = manage (new Button);
682 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
683 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
684 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
686 Button* summary_arrows_left_right = manage (new Button);
687 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
688 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
689 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
691 VBox* summary_arrows_left = manage (new VBox);
692 summary_arrows_left->pack_start (*summary_arrows_left_left);
693 summary_arrows_left->pack_start (*summary_arrows_left_right);
695 Button* summary_arrows_right_up = manage (new Button);
696 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
697 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
698 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
700 Button* summary_arrows_right_down = manage (new Button);
701 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
702 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
703 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
705 VBox* summary_arrows_right = manage (new VBox);
706 summary_arrows_right->pack_start (*summary_arrows_right_up);
707 summary_arrows_right->pack_start (*summary_arrows_right_down);
709 Frame* summary_frame = manage (new Frame);
710 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
712 summary_frame->add (*_summary);
713 summary_frame->show ();
715 _summary_hbox.pack_start (*summary_arrows_left, false, false);
716 _summary_hbox.pack_start (*summary_frame, true, true);
717 _summary_hbox.pack_start (*summary_arrows_right, false, false);
719 if (!ARDOUR::Profile->get_trx()) {
720 editor_summary_pane.pack2 (_summary_hbox);
723 edit_pane.pack1 (editor_summary_pane, true, true);
724 if (!ARDOUR::Profile->get_trx()) {
725 edit_pane.pack2 (_the_notebook, false, true);
728 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
730 /* XXX: editor_summary_pane might need similar to the edit_pane */
732 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
734 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
735 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
737 top_hbox.pack_start (toolbar_frame);
739 HBox *hbox = manage (new HBox);
740 hbox->pack_start (edit_pane, true, true);
742 global_vpacker.pack_start (top_hbox, false, false);
743 global_vpacker.pack_start (*hbox, true, true);
744 global_hpacker.pack_start (global_vpacker, true, true);
746 /* need to show the "contents" widget so that notebook will show if tab is switched to
749 global_hpacker.show ();
751 /* register actions now so that set_state() can find them and set toggles/checks etc */
754 /* when we start using our own keybinding system for the editor, this
755 * will be uncommented
761 _playlist_selector = new PlaylistSelector();
762 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
764 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
768 nudge_forward_button.set_name ("nudge button");
769 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
771 nudge_backward_button.set_name ("nudge button");
772 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
774 fade_context_menu.set_name ("ArdourContextMenu");
776 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
778 /* allow external control surfaces/protocols to do various things */
780 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
781 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
782 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
783 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
784 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
785 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
786 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
787 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
788 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
789 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
790 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
791 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
792 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
793 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
795 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
796 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
797 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
798 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
799 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
801 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
803 /* problematic: has to return a value and thus cannot be x-thread */
805 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
807 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
808 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
810 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
812 _ignore_region_action = false;
813 _last_region_menu_was_main = false;
814 _popup_region_menu_item = 0;
816 _ignore_follow_edits = false;
818 _show_marker_lines = false;
820 /* Button bindings */
822 button_bindings = new Bindings;
824 XMLNode* node = button_settings();
826 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
827 button_bindings->load (**i);
833 /* grab current parameter state */
834 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
835 UIConfiguration::instance().map_parameters (pc);
837 setup_fade_images ();
844 delete button_bindings;
846 delete _route_groups;
847 delete _track_canvas_viewport;
850 delete quantize_dialog;
856 delete _playlist_selector;
858 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
864 Editor::button_settings () const
866 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
867 XMLNode* node = find_named_node (*settings, X_("Buttons"));
870 node = new XMLNode (X_("Buttons"));
877 Editor::get_smart_mode () const
879 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
883 Editor::catch_vanishing_regionview (RegionView *rv)
885 /* note: the selection will take care of the vanishing
886 audioregionview by itself.
889 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
893 if (clicked_regionview == rv) {
894 clicked_regionview = 0;
897 if (entered_regionview == rv) {
898 set_entered_regionview (0);
901 if (!_all_region_actions_sensitized) {
902 sensitize_all_region_actions (true);
907 Editor::set_entered_regionview (RegionView* rv)
909 if (rv == entered_regionview) {
913 if (entered_regionview) {
914 entered_regionview->exited ();
917 entered_regionview = rv;
919 if (entered_regionview != 0) {
920 entered_regionview->entered ();
923 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
924 /* This RegionView entry might have changed what region actions
925 are allowed, so sensitize them all in case a key is pressed.
927 sensitize_all_region_actions (true);
932 Editor::set_entered_track (TimeAxisView* tav)
935 entered_track->exited ();
941 entered_track->entered ();
946 Editor::instant_save ()
948 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
953 _session->add_instant_xml(get_state());
955 Config->add_instant_xml(get_state());
960 Editor::control_vertical_zoom_in_all ()
962 tav_zoom_smooth (false, true);
966 Editor::control_vertical_zoom_out_all ()
968 tav_zoom_smooth (true, true);
972 Editor::control_vertical_zoom_in_selected ()
974 tav_zoom_smooth (false, false);
978 Editor::control_vertical_zoom_out_selected ()
980 tav_zoom_smooth (true, false);
984 Editor::control_view (uint32_t view)
986 goto_visual_state (view);
990 Editor::control_unselect ()
992 selection->clear_tracks ();
996 Editor::control_select (uint32_t rid, Selection::Operation op)
998 /* handles the (static) signal from the ControlProtocol class that
999 * requests setting the selected track to a given RID
1006 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1012 TimeAxisView* tav = axis_view_from_route (r);
1016 case Selection::Add:
1017 selection->add (tav);
1019 case Selection::Toggle:
1020 selection->toggle (tav);
1022 case Selection::Extend:
1024 case Selection::Set:
1025 selection->set (tav);
1029 selection->clear_tracks ();
1034 Editor::control_step_tracks_up ()
1036 scroll_tracks_up_line ();
1040 Editor::control_step_tracks_down ()
1042 scroll_tracks_down_line ();
1046 Editor::control_scroll (float fraction)
1048 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1054 double step = fraction * current_page_samples();
1057 _control_scroll_target is an optional<T>
1059 it acts like a pointer to an framepos_t, with
1060 a operator conversion to boolean to check
1061 that it has a value could possibly use
1062 playhead_cursor->current_frame to store the
1063 value and a boolean in the class to know
1064 when it's out of date
1067 if (!_control_scroll_target) {
1068 _control_scroll_target = _session->transport_frame();
1069 _dragging_playhead = true;
1072 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1073 *_control_scroll_target = 0;
1074 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1075 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1077 *_control_scroll_target += (framepos_t) trunc (step);
1080 /* move visuals, we'll catch up with it later */
1082 playhead_cursor->set_position (*_control_scroll_target);
1083 UpdateAllTransportClocks (*_control_scroll_target);
1085 if (*_control_scroll_target > (current_page_samples() / 2)) {
1086 /* try to center PH in window */
1087 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1093 Now we do a timeout to actually bring the session to the right place
1094 according to the playhead. This is to avoid reading disk buffers on every
1095 call to control_scroll, which is driven by ScrollTimeline and therefore
1096 probably by a control surface wheel which can generate lots of events.
1098 /* cancel the existing timeout */
1100 control_scroll_connection.disconnect ();
1102 /* add the next timeout */
1104 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1108 Editor::deferred_control_scroll (framepos_t /*target*/)
1110 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1111 // reset for next stream
1112 _control_scroll_target = boost::none;
1113 _dragging_playhead = false;
1118 Editor::access_action (std::string action_group, std::string action_item)
1124 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1127 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1135 Editor::on_realize ()
1139 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1140 start_lock_event_timing ();
1145 Editor::start_lock_event_timing ()
1147 /* check if we should lock the GUI every 30 seconds */
1149 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1153 Editor::generic_event_handler (GdkEvent* ev)
1156 case GDK_BUTTON_PRESS:
1157 case GDK_BUTTON_RELEASE:
1158 case GDK_MOTION_NOTIFY:
1160 case GDK_KEY_RELEASE:
1161 if (contents().is_mapped()) {
1162 gettimeofday (&last_event_time, 0);
1166 case GDK_LEAVE_NOTIFY:
1167 switch (ev->crossing.detail) {
1168 case GDK_NOTIFY_UNKNOWN:
1169 case GDK_NOTIFY_INFERIOR:
1170 case GDK_NOTIFY_ANCESTOR:
1172 case GDK_NOTIFY_VIRTUAL:
1173 case GDK_NOTIFY_NONLINEAR:
1174 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1175 /* leaving window, so reset focus, thus ending any and
1176 all text entry operations.
1191 Editor::lock_timeout_callback ()
1193 struct timeval now, delta;
1195 gettimeofday (&now, 0);
1197 timersub (&now, &last_event_time, &delta);
1199 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1201 /* don't call again. Returning false will effectively
1202 disconnect us from the timer callback.
1204 unlock() will call start_lock_event_timing() to get things
1214 Editor::map_position_change (framepos_t frame)
1216 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1218 if (_session == 0) {
1222 if (_follow_playhead) {
1223 center_screen (frame);
1226 playhead_cursor->set_position (frame);
1230 Editor::center_screen (framepos_t frame)
1232 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1234 /* if we're off the page, then scroll.
1237 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1238 center_screen_internal (frame, page);
1243 Editor::center_screen_internal (framepos_t frame, float page)
1248 frame -= (framepos_t) page;
1253 reset_x_origin (frame);
1258 Editor::update_title ()
1260 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1262 if (!own_window()) {
1267 bool dirty = _session->dirty();
1269 string session_name;
1271 if (_session->snap_name() != _session->name()) {
1272 session_name = _session->snap_name();
1274 session_name = _session->name();
1278 session_name = "*" + session_name;
1281 WindowTitle title(session_name);
1282 title += Glib::get_application_name();
1283 own_window()->set_title (title.get_string());
1285 /* ::session_going_away() will have taken care of it */
1290 Editor::set_session (Session *t)
1292 SessionHandlePtr::set_session (t);
1298 _playlist_selector->set_session (_session);
1299 nudge_clock->set_session (_session);
1300 _summary->set_session (_session);
1301 _group_tabs->set_session (_session);
1302 _route_groups->set_session (_session);
1303 _regions->set_session (_session);
1304 _snapshots->set_session (_session);
1305 _routes->set_session (_session);
1306 _locations->set_session (_session);
1308 if (rhythm_ferret) {
1309 rhythm_ferret->set_session (_session);
1312 if (analysis_window) {
1313 analysis_window->set_session (_session);
1317 sfbrowser->set_session (_session);
1320 compute_fixed_ruler_scale ();
1322 /* Make sure we have auto loop and auto punch ranges */
1324 Location* loc = _session->locations()->auto_loop_location();
1326 loc->set_name (_("Loop"));
1329 loc = _session->locations()->auto_punch_location();
1332 loc->set_name (_("Punch"));
1335 refresh_location_display ();
1337 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1338 the selected Marker; this needs the LocationMarker list to be available.
1340 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1341 set_state (*node, Stateful::loading_state_version);
1343 /* catch up with the playhead */
1345 _session->request_locate (playhead_cursor->current_frame ());
1346 _pending_initial_locate = true;
1350 /* These signals can all be emitted by a non-GUI thread. Therefore the
1351 handlers for them must not attempt to directly interact with the GUI,
1352 but use PBD::Signal<T>::connect() which accepts an event loop
1353 ("context") where the handler will be asked to run.
1356 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1357 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1358 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1359 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1360 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1361 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1362 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1363 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1364 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1365 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1366 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1367 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1368 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1370 playhead_cursor->show ();
1372 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1373 Config->map_parameters (pc);
1374 _session->config.map_parameters (pc);
1376 restore_ruler_visibility ();
1377 //tempo_map_changed (PropertyChange (0));
1378 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1380 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1381 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1384 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1385 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1388 switch (_snap_type) {
1389 case SnapToRegionStart:
1390 case SnapToRegionEnd:
1391 case SnapToRegionSync:
1392 case SnapToRegionBoundary:
1393 build_region_boundary_cache ();
1400 /* register for undo history */
1401 _session->register_with_memento_command_factory(id(), this);
1402 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1404 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1406 start_updating_meters ();
1410 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1412 if (a->get_name() == "RegionMenu") {
1413 /* When the main menu's region menu is opened, we setup the actions so that they look right
1414 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1415 so we resensitize all region actions when the entered regionview or the region selection
1416 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1417 happens after the region context menu is opened. So we set a flag here, too.
1421 sensitize_the_right_region_actions ();
1422 _last_region_menu_was_main = true;
1427 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1429 using namespace Menu_Helpers;
1431 void (Editor::*emf)(FadeShape);
1432 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1435 images = &_xfade_in_images;
1436 emf = &Editor::set_fade_in_shape;
1438 images = &_xfade_out_images;
1439 emf = &Editor::set_fade_out_shape;
1444 _("Linear (for highly correlated material)"),
1445 *(*images)[FadeLinear],
1446 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1450 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1454 _("Constant power"),
1455 *(*images)[FadeConstantPower],
1456 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1459 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1464 *(*images)[FadeSymmetric],
1465 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1469 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1474 *(*images)[FadeSlow],
1475 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1478 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1483 *(*images)[FadeFast],
1484 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1487 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1490 /** Pop up a context menu for when the user clicks on a start crossfade */
1492 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1494 using namespace Menu_Helpers;
1495 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1500 MenuList& items (xfade_in_context_menu.items());
1503 if (arv->audio_region()->fade_in_active()) {
1504 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1506 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1509 items.push_back (SeparatorElem());
1510 fill_xfade_menu (items, true);
1512 xfade_in_context_menu.popup (button, time);
1515 /** Pop up a context menu for when the user clicks on an end crossfade */
1517 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1519 using namespace Menu_Helpers;
1520 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1525 MenuList& items (xfade_out_context_menu.items());
1528 if (arv->audio_region()->fade_out_active()) {
1529 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1531 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1534 items.push_back (SeparatorElem());
1535 fill_xfade_menu (items, false);
1537 xfade_out_context_menu.popup (button, time);
1541 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1543 using namespace Menu_Helpers;
1544 Menu* (Editor::*build_menu_function)();
1547 switch (item_type) {
1549 case RegionViewName:
1550 case RegionViewNameHighlight:
1551 case LeftFrameHandle:
1552 case RightFrameHandle:
1553 if (with_selection) {
1554 build_menu_function = &Editor::build_track_selection_context_menu;
1556 build_menu_function = &Editor::build_track_region_context_menu;
1561 if (with_selection) {
1562 build_menu_function = &Editor::build_track_selection_context_menu;
1564 build_menu_function = &Editor::build_track_context_menu;
1569 if (clicked_routeview->track()) {
1570 build_menu_function = &Editor::build_track_context_menu;
1572 build_menu_function = &Editor::build_track_bus_context_menu;
1577 /* probably shouldn't happen but if it does, we don't care */
1581 menu = (this->*build_menu_function)();
1582 menu->set_name ("ArdourContextMenu");
1584 /* now handle specific situations */
1586 switch (item_type) {
1588 case RegionViewName:
1589 case RegionViewNameHighlight:
1590 case LeftFrameHandle:
1591 case RightFrameHandle:
1592 if (!with_selection) {
1593 if (region_edit_menu_split_item) {
1594 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1595 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1597 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1600 if (region_edit_menu_split_multichannel_item) {
1601 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1602 region_edit_menu_split_multichannel_item->set_sensitive (true);
1604 region_edit_menu_split_multichannel_item->set_sensitive (false);
1617 /* probably shouldn't happen but if it does, we don't care */
1621 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1623 /* Bounce to disk */
1625 using namespace Menu_Helpers;
1626 MenuList& edit_items = menu->items();
1628 edit_items.push_back (SeparatorElem());
1630 switch (clicked_routeview->audio_track()->freeze_state()) {
1631 case AudioTrack::NoFreeze:
1632 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1635 case AudioTrack::Frozen:
1636 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1639 case AudioTrack::UnFrozen:
1640 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1646 if (item_type == StreamItem && clicked_routeview) {
1647 clicked_routeview->build_underlay_menu(menu);
1650 /* When the region menu is opened, we setup the actions so that they look right
1653 sensitize_the_right_region_actions ();
1654 _last_region_menu_was_main = false;
1656 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1657 menu->popup (button, time);
1661 Editor::build_track_context_menu ()
1663 using namespace Menu_Helpers;
1665 MenuList& edit_items = track_context_menu.items();
1668 add_dstream_context_items (edit_items);
1669 return &track_context_menu;
1673 Editor::build_track_bus_context_menu ()
1675 using namespace Menu_Helpers;
1677 MenuList& edit_items = track_context_menu.items();
1680 add_bus_context_items (edit_items);
1681 return &track_context_menu;
1685 Editor::build_track_region_context_menu ()
1687 using namespace Menu_Helpers;
1688 MenuList& edit_items = track_region_context_menu.items();
1691 /* we've just cleared the track region context menu, so the menu that these
1692 two items were on will have disappeared; stop them dangling.
1694 region_edit_menu_split_item = 0;
1695 region_edit_menu_split_multichannel_item = 0;
1697 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1700 boost::shared_ptr<Track> tr;
1701 boost::shared_ptr<Playlist> pl;
1703 if ((tr = rtv->track())) {
1704 add_region_context_items (edit_items, tr);
1708 add_dstream_context_items (edit_items);
1710 return &track_region_context_menu;
1714 Editor::analyze_region_selection ()
1716 if (analysis_window == 0) {
1717 analysis_window = new AnalysisWindow();
1720 analysis_window->set_session(_session);
1722 analysis_window->show_all();
1725 analysis_window->set_regionmode();
1726 analysis_window->analyze();
1728 analysis_window->present();
1732 Editor::analyze_range_selection()
1734 if (analysis_window == 0) {
1735 analysis_window = new AnalysisWindow();
1738 analysis_window->set_session(_session);
1740 analysis_window->show_all();
1743 analysis_window->set_rangemode();
1744 analysis_window->analyze();
1746 analysis_window->present();
1750 Editor::build_track_selection_context_menu ()
1752 using namespace Menu_Helpers;
1753 MenuList& edit_items = track_selection_context_menu.items();
1754 edit_items.clear ();
1756 add_selection_context_items (edit_items);
1757 // edit_items.push_back (SeparatorElem());
1758 // add_dstream_context_items (edit_items);
1760 return &track_selection_context_menu;
1764 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1766 using namespace Menu_Helpers;
1768 /* OK, stick the region submenu at the top of the list, and then add
1772 RegionSelection rs = get_regions_from_selection_and_entered ();
1774 string::size_type pos = 0;
1775 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1777 /* we have to hack up the region name because "_" has a special
1778 meaning for menu titles.
1781 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1782 menu_item_name.replace (pos, 1, "__");
1786 if (_popup_region_menu_item == 0) {
1787 _popup_region_menu_item = new MenuItem (menu_item_name);
1788 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1789 _popup_region_menu_item->show ();
1791 _popup_region_menu_item->set_label (menu_item_name);
1794 /* No latering allowed in later is higher layering model */
1795 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1796 if (act && Config->get_layer_model() == LaterHigher) {
1797 act->set_sensitive (false);
1799 act->set_sensitive (true);
1802 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1804 edit_items.push_back (*_popup_region_menu_item);
1805 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1806 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1808 edit_items.push_back (SeparatorElem());
1811 /** Add context menu items relevant to selection ranges.
1812 * @param edit_items List to add the items to.
1815 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1817 using namespace Menu_Helpers;
1819 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1820 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1822 edit_items.push_back (SeparatorElem());
1823 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1825 edit_items.push_back (SeparatorElem());
1826 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1828 edit_items.push_back (SeparatorElem());
1830 edit_items.push_back (
1832 _("Move Range Start to Previous Region Boundary"),
1833 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1837 edit_items.push_back (
1839 _("Move Range Start to Next Region Boundary"),
1840 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1844 edit_items.push_back (
1846 _("Move Range End to Previous Region Boundary"),
1847 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1851 edit_items.push_back (
1853 _("Move Range End to Next Region Boundary"),
1854 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1858 edit_items.push_back (SeparatorElem());
1859 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1860 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1862 edit_items.push_back (SeparatorElem());
1863 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1865 edit_items.push_back (SeparatorElem());
1866 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1867 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1868 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1870 edit_items.push_back (SeparatorElem());
1871 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1873 edit_items.push_back (SeparatorElem());
1874 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1875 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1877 edit_items.push_back (SeparatorElem());
1878 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1879 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1880 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1881 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1882 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1883 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1884 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1890 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1892 using namespace Menu_Helpers;
1896 Menu *play_menu = manage (new Menu);
1897 MenuList& play_items = play_menu->items();
1898 play_menu->set_name ("ArdourContextMenu");
1900 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1901 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1902 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1903 play_items.push_back (SeparatorElem());
1904 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1906 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1910 Menu *select_menu = manage (new Menu);
1911 MenuList& select_items = select_menu->items();
1912 select_menu->set_name ("ArdourContextMenu");
1914 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1915 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1916 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1917 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1918 select_items.push_back (SeparatorElem());
1919 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1920 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1921 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
1922 select_items.push_back (SeparatorElem());
1923 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
1924 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
1925 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1926 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1927 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1928 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1929 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1931 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1935 Menu *cutnpaste_menu = manage (new Menu);
1936 MenuList& cutnpaste_items = cutnpaste_menu->items();
1937 cutnpaste_menu->set_name ("ArdourContextMenu");
1939 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1940 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1941 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1943 cutnpaste_items.push_back (SeparatorElem());
1945 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1946 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1948 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1950 /* Adding new material */
1952 edit_items.push_back (SeparatorElem());
1953 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1954 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1958 Menu *nudge_menu = manage (new Menu());
1959 MenuList& nudge_items = nudge_menu->items();
1960 nudge_menu->set_name ("ArdourContextMenu");
1962 edit_items.push_back (SeparatorElem());
1963 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1964 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1965 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1966 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1968 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1972 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1974 using namespace Menu_Helpers;
1978 Menu *play_menu = manage (new Menu);
1979 MenuList& play_items = play_menu->items();
1980 play_menu->set_name ("ArdourContextMenu");
1982 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1983 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1984 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1988 Menu *select_menu = manage (new Menu);
1989 MenuList& select_items = select_menu->items();
1990 select_menu->set_name ("ArdourContextMenu");
1992 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1993 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1994 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1995 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1996 select_items.push_back (SeparatorElem());
1997 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
1998 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
1999 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2000 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2002 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2006 Menu *cutnpaste_menu = manage (new Menu);
2007 MenuList& cutnpaste_items = cutnpaste_menu->items();
2008 cutnpaste_menu->set_name ("ArdourContextMenu");
2010 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2011 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2012 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2014 Menu *nudge_menu = manage (new Menu());
2015 MenuList& nudge_items = nudge_menu->items();
2016 nudge_menu->set_name ("ArdourContextMenu");
2018 edit_items.push_back (SeparatorElem());
2019 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2020 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2021 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2022 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2024 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2028 Editor::snap_type() const
2034 Editor::snap_mode() const
2040 Editor::set_snap_to (SnapType st)
2042 unsigned int snap_ind = (unsigned int)st;
2044 if (internal_editing()) {
2045 internal_snap_type = st;
2047 pre_internal_snap_type = st;
2052 if (snap_ind > snap_type_strings.size() - 1) {
2054 _snap_type = (SnapType)snap_ind;
2057 string str = snap_type_strings[snap_ind];
2059 if (str != snap_type_selector.get_text()) {
2060 snap_type_selector.set_text (str);
2065 switch (_snap_type) {
2066 case SnapToBeatDiv128:
2067 case SnapToBeatDiv64:
2068 case SnapToBeatDiv32:
2069 case SnapToBeatDiv28:
2070 case SnapToBeatDiv24:
2071 case SnapToBeatDiv20:
2072 case SnapToBeatDiv16:
2073 case SnapToBeatDiv14:
2074 case SnapToBeatDiv12:
2075 case SnapToBeatDiv10:
2076 case SnapToBeatDiv8:
2077 case SnapToBeatDiv7:
2078 case SnapToBeatDiv6:
2079 case SnapToBeatDiv5:
2080 case SnapToBeatDiv4:
2081 case SnapToBeatDiv3:
2082 case SnapToBeatDiv2: {
2083 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2084 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2086 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2087 current_bbt_points_begin, current_bbt_points_end);
2088 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2089 current_bbt_points_begin, current_bbt_points_end);
2090 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2094 case SnapToRegionStart:
2095 case SnapToRegionEnd:
2096 case SnapToRegionSync:
2097 case SnapToRegionBoundary:
2098 build_region_boundary_cache ();
2106 redisplay_tempo (false);
2108 SnapChanged (); /* EMIT SIGNAL */
2112 Editor::set_snap_mode (SnapMode mode)
2114 string str = snap_mode_strings[(int)mode];
2116 if (internal_editing()) {
2117 internal_snap_mode = mode;
2119 pre_internal_snap_mode = mode;
2124 if (str != snap_mode_selector.get_text ()) {
2125 snap_mode_selector.set_text (str);
2132 Editor::set_edit_point_preference (EditPoint ep, bool force)
2134 bool changed = (_edit_point != ep);
2137 if (Profile->get_mixbus())
2138 if (ep == EditAtSelectedMarker)
2139 ep = EditAtPlayhead;
2141 string str = edit_point_strings[(int)ep];
2142 if (str != edit_point_selector.get_text ()) {
2143 edit_point_selector.set_text (str);
2146 update_all_enter_cursors();
2148 if (!force && !changed) {
2152 const char* action=NULL;
2154 switch (_edit_point) {
2155 case EditAtPlayhead:
2156 action = "edit-at-playhead";
2158 case EditAtSelectedMarker:
2159 action = "edit-at-marker";
2162 action = "edit-at-mouse";
2166 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2168 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2172 bool in_track_canvas;
2174 if (!mouse_frame (foo, in_track_canvas)) {
2175 in_track_canvas = false;
2178 reset_canvas_action_sensitivity (in_track_canvas);
2184 Editor::set_state (const XMLNode& node, int version)
2186 const XMLProperty* prop;
2189 Tabbable::set_state (node, version);
2191 if (_session && (prop = node.property ("playhead"))) {
2193 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2195 playhead_cursor->set_position (pos);
2197 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2198 playhead_cursor->set_position (0);
2201 playhead_cursor->set_position (0);
2204 if ((prop = node.property ("mixer-width"))) {
2205 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2208 if ((prop = node.property ("zoom-focus"))) {
2209 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2212 if ((prop = node.property ("zoom"))) {
2213 /* older versions of ardour used floating point samples_per_pixel */
2214 double f = PBD::atof (prop->value());
2215 reset_zoom (llrintf (f));
2217 reset_zoom (samples_per_pixel);
2220 if ((prop = node.property ("visible-track-count"))) {
2221 set_visible_track_count (PBD::atoi (prop->value()));
2224 if ((prop = node.property ("snap-to"))) {
2225 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2228 if ((prop = node.property ("snap-mode"))) {
2229 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2232 if ((prop = node.property ("internal-snap-to"))) {
2233 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2236 if ((prop = node.property ("internal-snap-mode"))) {
2237 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2240 if ((prop = node.property ("pre-internal-snap-to"))) {
2241 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2244 if ((prop = node.property ("pre-internal-snap-mode"))) {
2245 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2248 if ((prop = node.property ("mouse-mode"))) {
2249 MouseMode m = str2mousemode(prop->value());
2250 set_mouse_mode (m, true);
2252 set_mouse_mode (MouseObject, true);
2255 if ((prop = node.property ("left-frame")) != 0) {
2257 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2261 reset_x_origin (pos);
2265 if ((prop = node.property ("y-origin")) != 0) {
2266 reset_y_origin (atof (prop->value ()));
2269 if ((prop = node.property ("join-object-range"))) {
2270 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2271 bool yn = string_is_affirmative (prop->value());
2273 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2274 tact->set_active (!yn);
2275 tact->set_active (yn);
2277 set_mouse_mode(mouse_mode, true);
2280 if ((prop = node.property ("edit-point"))) {
2281 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2284 if ((prop = node.property ("show-measures"))) {
2285 bool yn = string_is_affirmative (prop->value());
2286 _show_measures = yn;
2289 if ((prop = node.property ("follow-playhead"))) {
2290 bool yn = string_is_affirmative (prop->value());
2291 set_follow_playhead (yn);
2294 if ((prop = node.property ("stationary-playhead"))) {
2295 bool yn = string_is_affirmative (prop->value());
2296 set_stationary_playhead (yn);
2299 if ((prop = node.property ("region-list-sort-type"))) {
2300 RegionListSortType st;
2301 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2304 if ((prop = node.property ("show-editor-mixer"))) {
2306 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2309 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2310 bool yn = string_is_affirmative (prop->value());
2312 /* do it twice to force the change */
2314 tact->set_active (!yn);
2315 tact->set_active (yn);
2318 if ((prop = node.property ("show-editor-list"))) {
2320 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2323 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2324 bool yn = string_is_affirmative (prop->value());
2326 /* do it twice to force the change */
2328 tact->set_active (!yn);
2329 tact->set_active (yn);
2332 if ((prop = node.property (X_("editor-list-page")))) {
2333 _the_notebook.set_current_page (atoi (prop->value ()));
2336 if ((prop = node.property (X_("show-marker-lines")))) {
2337 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2339 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2340 bool yn = string_is_affirmative (prop->value ());
2342 tact->set_active (!yn);
2343 tact->set_active (yn);
2346 XMLNodeList children = node.children ();
2347 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2348 selection->set_state (**i, Stateful::current_state_version);
2349 _regions->set_state (**i);
2352 if ((prop = node.property ("maximised"))) {
2353 bool yn = string_is_affirmative (prop->value());
2354 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2356 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2357 bool fs = tact && tact->get_active();
2359 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2363 if ((prop = node.property ("nudge-clock-value"))) {
2365 sscanf (prop->value().c_str(), "%" PRId64, &f);
2366 nudge_clock->set (f);
2368 nudge_clock->set_mode (AudioClock::Timecode);
2369 nudge_clock->set (_session->frame_rate() * 5, true);
2374 * Not all properties may have been in XML, but
2375 * those that are linked to a private variable may need changing
2380 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2382 yn = _show_measures;
2383 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2384 /* do it twice to force the change */
2385 tact->set_active (!yn);
2386 tact->set_active (yn);
2389 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2390 yn = _follow_playhead;
2392 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2393 if (tact->get_active() != yn) {
2394 tact->set_active (yn);
2398 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2399 yn = _stationary_playhead;
2401 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2402 if (tact->get_active() != yn) {
2403 tact->set_active (yn);
2412 Editor::get_state ()
2414 XMLNode* node = new XMLNode (X_("Editor"));
2417 id().print (buf, sizeof (buf));
2418 node->add_property ("id", buf);
2420 node->add_child_nocopy (Tabbable::get_state());
2422 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2423 node->add_property("edit-horizontal-pane-pos", string(buf));
2424 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2425 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2426 node->add_property("edit-vertical-pane-pos", string(buf));
2428 maybe_add_mixer_strip_width (*node);
2430 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2432 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2433 node->add_property ("zoom", buf);
2434 node->add_property ("snap-to", enum_2_string (_snap_type));
2435 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2436 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2437 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2438 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2439 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2440 node->add_property ("edit-point", enum_2_string (_edit_point));
2441 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2442 node->add_property ("visible-track-count", buf);
2444 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2445 node->add_property ("playhead", buf);
2446 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2447 node->add_property ("left-frame", buf);
2448 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2449 node->add_property ("y-origin", buf);
2451 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2452 node->add_property ("maximised", _maximised ? "yes" : "no");
2453 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2454 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2455 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2456 node->add_property ("mouse-mode", enum2str(mouse_mode));
2457 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2459 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2461 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2462 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2465 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2467 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2468 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2471 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2472 node->add_property (X_("editor-list-page"), buf);
2474 if (button_bindings) {
2475 XMLNode* bb = new XMLNode (X_("Buttons"));
2476 button_bindings->save (*bb);
2477 node->add_child_nocopy (*bb);
2480 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2482 node->add_child_nocopy (selection->get_state ());
2483 node->add_child_nocopy (_regions->get_state ());
2485 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2486 node->add_property ("nudge-clock-value", buf);
2491 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2492 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2494 * @return pair: TimeAxisView that y is over, layer index.
2496 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2497 * in stacked or expanded region display mode, otherwise 0.
2499 std::pair<TimeAxisView *, double>
2500 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2502 if (!trackview_relative_offset) {
2503 y -= _trackview_group->canvas_origin().y;
2507 return std::make_pair ( (TimeAxisView *) 0, 0);
2510 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2512 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2519 return std::make_pair ( (TimeAxisView *) 0, 0);
2522 /** Snap a position to the grid, if appropriate, taking into account current
2523 * grid settings and also the state of any snap modifier keys that may be pressed.
2524 * @param start Position to snap.
2525 * @param event Event to get current key modifier information from, or 0.
2528 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2530 if (!_session || !event) {
2534 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2535 if (_snap_mode == SnapOff) {
2536 snap_to_internal (start, direction, for_mark);
2539 if (_snap_mode != SnapOff) {
2540 snap_to_internal (start, direction, for_mark);
2541 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2542 /* SnapOff, but we pressed the snap_delta modifier */
2543 snap_to_internal (start, direction, for_mark);
2549 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2551 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2555 snap_to_internal (start, direction, for_mark, ensure_snap);
2559 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2561 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2562 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2564 switch (_snap_type) {
2565 case SnapToTimecodeFrame:
2566 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2567 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2568 /* start is already on a whole timecode frame, do nothing */
2569 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2570 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2572 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2576 case SnapToTimecodeSeconds:
2577 if (_session->config.get_timecode_offset_negative()) {
2578 start += _session->config.get_timecode_offset ();
2580 start -= _session->config.get_timecode_offset ();
2582 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2583 (start % one_timecode_second == 0)) {
2584 /* start is already on a whole second, do nothing */
2585 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2586 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2588 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2591 if (_session->config.get_timecode_offset_negative()) {
2592 start -= _session->config.get_timecode_offset ();
2594 start += _session->config.get_timecode_offset ();
2598 case SnapToTimecodeMinutes:
2599 if (_session->config.get_timecode_offset_negative()) {
2600 start += _session->config.get_timecode_offset ();
2602 start -= _session->config.get_timecode_offset ();
2604 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2605 (start % one_timecode_minute == 0)) {
2606 /* start is already on a whole minute, do nothing */
2607 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2608 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2610 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2612 if (_session->config.get_timecode_offset_negative()) {
2613 start -= _session->config.get_timecode_offset ();
2615 start += _session->config.get_timecode_offset ();
2619 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2620 abort(); /*NOTREACHED*/
2625 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2627 const framepos_t one_second = _session->frame_rate();
2628 const framepos_t one_minute = _session->frame_rate() * 60;
2629 framepos_t presnap = start;
2633 switch (_snap_type) {
2634 case SnapToTimecodeFrame:
2635 case SnapToTimecodeSeconds:
2636 case SnapToTimecodeMinutes:
2637 return timecode_snap_to_internal (start, direction, for_mark);
2640 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2641 start % (one_second/75) == 0) {
2642 /* start is already on a whole CD frame, do nothing */
2643 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2644 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2646 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2651 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2652 start % one_second == 0) {
2653 /* start is already on a whole second, do nothing */
2654 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2655 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2657 start = (framepos_t) floor ((double) start / one_second) * one_second;
2662 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2663 start % one_minute == 0) {
2664 /* start is already on a whole minute, do nothing */
2665 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2666 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2668 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2673 start = _session->tempo_map().round_to_bar (start, direction);
2677 start = _session->tempo_map().round_to_beat (start, direction);
2680 case SnapToBeatDiv128:
2681 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2683 case SnapToBeatDiv64:
2684 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2686 case SnapToBeatDiv32:
2687 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2689 case SnapToBeatDiv28:
2690 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2692 case SnapToBeatDiv24:
2693 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2695 case SnapToBeatDiv20:
2696 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2698 case SnapToBeatDiv16:
2699 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2701 case SnapToBeatDiv14:
2702 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2704 case SnapToBeatDiv12:
2705 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2707 case SnapToBeatDiv10:
2708 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2710 case SnapToBeatDiv8:
2711 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2713 case SnapToBeatDiv7:
2714 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2716 case SnapToBeatDiv6:
2717 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2719 case SnapToBeatDiv5:
2720 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2722 case SnapToBeatDiv4:
2723 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2725 case SnapToBeatDiv3:
2726 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2728 case SnapToBeatDiv2:
2729 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2737 _session->locations()->marks_either_side (start, before, after);
2739 if (before == max_framepos && after == max_framepos) {
2740 /* No marks to snap to, so just don't snap */
2742 } else if (before == max_framepos) {
2744 } else if (after == max_framepos) {
2746 } else if (before != max_framepos && after != max_framepos) {
2747 /* have before and after */
2748 if ((start - before) < (after - start)) {
2757 case SnapToRegionStart:
2758 case SnapToRegionEnd:
2759 case SnapToRegionSync:
2760 case SnapToRegionBoundary:
2761 if (!region_boundary_cache.empty()) {
2763 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2764 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2766 if (direction > 0) {
2767 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2769 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2772 if (next != region_boundary_cache.begin ()) {
2777 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2778 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2780 if (start > (p + n) / 2) {
2789 switch (_snap_mode) {
2799 if (presnap > start) {
2800 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2804 } else if (presnap < start) {
2805 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2811 /* handled at entry */
2819 Editor::setup_toolbar ()
2821 HBox* mode_box = manage(new HBox);
2822 mode_box->set_border_width (2);
2823 mode_box->set_spacing(2);
2825 HBox* mouse_mode_box = manage (new HBox);
2826 HBox* mouse_mode_hbox = manage (new HBox);
2827 VBox* mouse_mode_vbox = manage (new VBox);
2828 Alignment* mouse_mode_align = manage (new Alignment);
2830 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2831 mouse_mode_size_group->add_widget (smart_mode_button);
2832 mouse_mode_size_group->add_widget (mouse_move_button);
2833 mouse_mode_size_group->add_widget (mouse_cut_button);
2834 mouse_mode_size_group->add_widget (mouse_select_button);
2835 mouse_mode_size_group->add_widget (mouse_timefx_button);
2836 mouse_mode_size_group->add_widget (mouse_audition_button);
2837 mouse_mode_size_group->add_widget (mouse_draw_button);
2838 mouse_mode_size_group->add_widget (mouse_content_button);
2840 mouse_mode_size_group->add_widget (zoom_in_button);
2841 mouse_mode_size_group->add_widget (zoom_out_button);
2842 mouse_mode_size_group->add_widget (zoom_preset_selector);
2843 mouse_mode_size_group->add_widget (zoom_out_full_button);
2844 mouse_mode_size_group->add_widget (zoom_focus_selector);
2846 mouse_mode_size_group->add_widget (tav_shrink_button);
2847 mouse_mode_size_group->add_widget (tav_expand_button);
2848 mouse_mode_size_group->add_widget (visible_tracks_selector);
2850 mouse_mode_size_group->add_widget (snap_type_selector);
2851 mouse_mode_size_group->add_widget (snap_mode_selector);
2853 mouse_mode_size_group->add_widget (edit_point_selector);
2854 mouse_mode_size_group->add_widget (edit_mode_selector);
2856 mouse_mode_size_group->add_widget (*nudge_clock);
2857 mouse_mode_size_group->add_widget (nudge_forward_button);
2858 mouse_mode_size_group->add_widget (nudge_backward_button);
2860 mouse_mode_hbox->set_spacing (2);
2862 if (!ARDOUR::Profile->get_trx()) {
2863 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2866 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2867 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2869 if (!ARDOUR::Profile->get_mixbus()) {
2870 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2873 if (!ARDOUR::Profile->get_trx()) {
2874 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2875 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2876 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2877 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2880 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2882 mouse_mode_align->add (*mouse_mode_vbox);
2883 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2885 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2887 edit_mode_selector.set_name ("mouse mode button");
2889 if (!ARDOUR::Profile->get_trx()) {
2890 mode_box->pack_start (edit_mode_selector, false, false);
2893 mode_box->pack_start (*mouse_mode_box, false, false);
2897 _zoom_box.set_spacing (2);
2898 _zoom_box.set_border_width (2);
2902 zoom_preset_selector.set_name ("zoom button");
2903 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2904 zoom_preset_selector.set_size_request (42, -1);
2906 zoom_in_button.set_name ("zoom button");
2907 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
2908 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2909 zoom_in_button.set_related_action (act);
2911 zoom_out_button.set_name ("zoom button");
2912 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
2913 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2914 zoom_out_button.set_related_action (act);
2916 zoom_out_full_button.set_name ("zoom button");
2917 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
2918 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2919 zoom_out_full_button.set_related_action (act);
2921 zoom_focus_selector.set_name ("zoom button");
2923 if (ARDOUR::Profile->get_mixbus()) {
2924 _zoom_box.pack_start (zoom_preset_selector, false, false);
2925 } else if (ARDOUR::Profile->get_trx()) {
2926 mode_box->pack_start (zoom_out_button, false, false);
2927 mode_box->pack_start (zoom_in_button, false, false);
2929 _zoom_box.pack_start (zoom_out_button, false, false);
2930 _zoom_box.pack_start (zoom_in_button, false, false);
2931 _zoom_box.pack_start (zoom_out_full_button, false, false);
2932 _zoom_box.pack_start (zoom_focus_selector, false, false);
2935 /* Track zoom buttons */
2936 visible_tracks_selector.set_name ("zoom button");
2937 if (Profile->get_mixbus()) {
2938 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2939 visible_tracks_selector.set_size_request (42, -1);
2941 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2944 tav_expand_button.set_name ("zoom button");
2945 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
2946 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2947 tav_expand_button.set_related_action (act);
2949 tav_shrink_button.set_name ("zoom button");
2950 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
2951 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2952 tav_shrink_button.set_related_action (act);
2954 if (ARDOUR::Profile->get_mixbus()) {
2955 _zoom_box.pack_start (visible_tracks_selector);
2956 } else if (ARDOUR::Profile->get_trx()) {
2957 _zoom_box.pack_start (tav_shrink_button);
2958 _zoom_box.pack_start (tav_expand_button);
2960 _zoom_box.pack_start (visible_tracks_selector);
2961 _zoom_box.pack_start (tav_shrink_button);
2962 _zoom_box.pack_start (tav_expand_button);
2965 snap_box.set_spacing (2);
2966 snap_box.set_border_width (2);
2968 snap_type_selector.set_name ("mouse mode button");
2970 snap_mode_selector.set_name ("mouse mode button");
2972 edit_point_selector.set_name ("mouse mode button");
2974 snap_box.pack_start (snap_mode_selector, false, false);
2975 snap_box.pack_start (snap_type_selector, false, false);
2976 snap_box.pack_start (edit_point_selector, false, false);
2980 HBox *nudge_box = manage (new HBox);
2981 nudge_box->set_spacing (2);
2982 nudge_box->set_border_width (2);
2984 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2985 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2987 nudge_box->pack_start (nudge_backward_button, false, false);
2988 nudge_box->pack_start (nudge_forward_button, false, false);
2989 nudge_box->pack_start (*nudge_clock, false, false);
2992 /* Pack everything in... */
2994 HBox* hbox = manage (new HBox);
2995 hbox->set_spacing(2);
2997 toolbar_hbox.set_spacing (2);
2998 toolbar_hbox.set_border_width (1);
3000 toolbar_hbox.pack_start (*mode_box, false, false);
3001 if (!ARDOUR::Profile->get_trx()) {
3002 toolbar_hbox.pack_start (_zoom_box, false, false);
3003 toolbar_hbox.pack_start (*hbox, false, false);
3006 if (!ARDOUR::Profile->get_trx()) {
3007 hbox->pack_start (snap_box, false, false);
3008 hbox->pack_start (*nudge_box, false, false);
3013 toolbar_base.set_name ("ToolBarBase");
3014 toolbar_base.add (toolbar_hbox);
3016 _toolbar_viewport.add (toolbar_base);
3017 /* stick to the required height but allow width to vary if there's not enough room */
3018 _toolbar_viewport.set_size_request (1, -1);
3020 toolbar_frame.set_shadow_type (SHADOW_OUT);
3021 toolbar_frame.set_name ("BaseFrame");
3022 toolbar_frame.add (_toolbar_viewport);
3026 Editor::build_edit_point_menu ()
3028 using namespace Menu_Helpers;
3030 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3031 if(!Profile->get_mixbus())
3032 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3033 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3035 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3039 Editor::build_edit_mode_menu ()
3041 using namespace Menu_Helpers;
3043 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3044 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3045 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3046 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3048 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3052 Editor::build_snap_mode_menu ()
3054 using namespace Menu_Helpers;
3056 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3057 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3058 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3060 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3064 Editor::build_snap_type_menu ()
3066 using namespace Menu_Helpers;
3068 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3069 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3070 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3071 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3072 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3073 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3074 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3075 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3076 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3077 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3078 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3079 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3080 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3081 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3082 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3083 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3084 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3085 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3086 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3087 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3088 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3089 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3090 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3091 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3092 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3093 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3094 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3095 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3096 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3097 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3099 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3104 Editor::setup_tooltips ()
3106 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3107 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3108 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3109 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3110 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3111 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3112 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3113 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3114 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3115 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3116 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3117 set_tooltip (zoom_in_button, _("Zoom In"));
3118 set_tooltip (zoom_out_button, _("Zoom Out"));
3119 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3120 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3121 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3122 set_tooltip (tav_expand_button, _("Expand Tracks"));
3123 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3124 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3125 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3126 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3127 set_tooltip (edit_point_selector, _("Edit Point"));
3128 set_tooltip (edit_mode_selector, _("Edit Mode"));
3129 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3133 Editor::convert_drop_to_paths (
3134 vector<string>& paths,
3135 const RefPtr<Gdk::DragContext>& /*context*/,
3138 const SelectionData& data,
3142 if (_session == 0) {
3146 vector<string> uris = data.get_uris();
3150 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3151 are actually URI lists. So do it by hand.
3154 if (data.get_target() != "text/plain") {
3158 /* Parse the "uri-list" format that Nautilus provides,
3159 where each pathname is delimited by \r\n.
3161 THERE MAY BE NO NULL TERMINATING CHAR!!!
3164 string txt = data.get_text();
3168 p = (char *) malloc (txt.length() + 1);
3169 txt.copy (p, txt.length(), 0);
3170 p[txt.length()] = '\0';
3176 while (g_ascii_isspace (*p))
3180 while (*q && (*q != '\n') && (*q != '\r')) {
3187 while (q > p && g_ascii_isspace (*q))
3192 uris.push_back (string (p, q - p + 1));
3196 p = strchr (p, '\n');
3208 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3209 if ((*i).substr (0,7) == "file://") {
3210 paths.push_back (Glib::filename_from_uri (*i));
3218 Editor::new_tempo_section ()
3223 Editor::map_transport_state ()
3225 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3227 if (_session && _session->transport_stopped()) {
3228 have_pending_keyboard_selection = false;
3231 update_loop_range_view ();
3237 Editor::begin_selection_op_history ()
3239 selection_op_cmd_depth = 0;
3240 selection_op_history_it = 0;
3242 while(!selection_op_history.empty()) {
3243 delete selection_op_history.front();
3244 selection_op_history.pop_front();
3247 selection_undo_action->set_sensitive (false);
3248 selection_redo_action->set_sensitive (false);
3249 selection_op_history.push_front (&_selection_memento->get_state ());
3253 Editor::begin_reversible_selection_op (string name)
3256 //cerr << name << endl;
3257 /* begin/commit pairs can be nested */
3258 selection_op_cmd_depth++;
3263 Editor::commit_reversible_selection_op ()
3266 if (selection_op_cmd_depth == 1) {
3268 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3270 The user has undone some selection ops and then made a new one,
3271 making anything earlier in the list invalid.
3274 list<XMLNode *>::iterator it = selection_op_history.begin();
3275 list<XMLNode *>::iterator e_it = it;
3276 advance (e_it, selection_op_history_it);
3278 for ( ; it != e_it; ++it) {
3281 selection_op_history.erase (selection_op_history.begin(), e_it);
3284 selection_op_history.push_front (&_selection_memento->get_state ());
3285 selection_op_history_it = 0;
3287 selection_undo_action->set_sensitive (true);
3288 selection_redo_action->set_sensitive (false);
3291 if (selection_op_cmd_depth > 0) {
3292 selection_op_cmd_depth--;
3298 Editor::undo_selection_op ()
3301 selection_op_history_it++;
3303 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3304 if (n == selection_op_history_it) {
3305 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3306 selection_redo_action->set_sensitive (true);
3310 /* is there an earlier entry? */
3311 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3312 selection_undo_action->set_sensitive (false);
3318 Editor::redo_selection_op ()
3321 if (selection_op_history_it > 0) {
3322 selection_op_history_it--;
3325 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3326 if (n == selection_op_history_it) {
3327 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3328 selection_undo_action->set_sensitive (true);
3333 if (selection_op_history_it == 0) {
3334 selection_redo_action->set_sensitive (false);
3340 Editor::begin_reversible_command (string name)
3343 before.push_back (&_selection_memento->get_state ());
3344 _session->begin_reversible_command (name);
3349 Editor::begin_reversible_command (GQuark q)
3352 before.push_back (&_selection_memento->get_state ());
3353 _session->begin_reversible_command (q);
3358 Editor::abort_reversible_command ()
3361 while(!before.empty()) {
3362 delete before.front();
3365 _session->abort_reversible_command ();
3370 Editor::commit_reversible_command ()
3373 if (before.size() == 1) {
3374 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3375 redo_action->set_sensitive(false);
3376 undo_action->set_sensitive(true);
3377 begin_selection_op_history ();
3380 if (before.empty()) {
3381 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3386 _session->commit_reversible_command ();
3391 Editor::history_changed ()
3395 if (undo_action && _session) {
3396 if (_session->undo_depth() == 0) {
3397 label = S_("Command|Undo");
3399 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3401 undo_action->property_label() = label;
3404 if (redo_action && _session) {
3405 if (_session->redo_depth() == 0) {
3407 redo_action->set_sensitive (false);
3409 label = string_compose(_("Redo (%1)"), _session->next_redo());
3410 redo_action->set_sensitive (true);
3412 redo_action->property_label() = label;
3417 Editor::duplicate_range (bool with_dialog)
3421 RegionSelection rs = get_regions_from_selection_and_entered ();
3423 if ( selection->time.length() == 0 && rs.empty()) {
3429 ArdourDialog win (_("Duplicate"));
3430 Label label (_("Number of duplications:"));
3431 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3432 SpinButton spinner (adjustment, 0.0, 1);
3435 win.get_vbox()->set_spacing (12);
3436 win.get_vbox()->pack_start (hbox);
3437 hbox.set_border_width (6);
3438 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3440 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3441 place, visually. so do this by hand.
3444 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3445 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3446 spinner.grab_focus();
3452 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3453 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3454 win.set_default_response (RESPONSE_ACCEPT);
3456 spinner.grab_focus ();
3458 switch (win.run ()) {
3459 case RESPONSE_ACCEPT:
3465 times = adjustment.get_value();
3468 if ((current_mouse_mode() == Editing::MouseRange)) {
3469 if (selection->time.length()) {
3470 duplicate_selection (times);
3472 } else if (get_smart_mode()) {
3473 if (selection->time.length()) {
3474 duplicate_selection (times);
3476 duplicate_some_regions (rs, times);
3478 duplicate_some_regions (rs, times);
3483 Editor::set_edit_mode (EditMode m)
3485 Config->set_edit_mode (m);
3489 Editor::cycle_edit_mode ()
3491 switch (Config->get_edit_mode()) {
3493 if (Profile->get_sae()) {
3494 Config->set_edit_mode (Lock);
3496 Config->set_edit_mode (Ripple);
3501 Config->set_edit_mode (Lock);
3504 Config->set_edit_mode (Slide);
3510 Editor::edit_mode_selection_done ( EditMode m )
3512 Config->set_edit_mode ( m );
3516 Editor::snap_type_selection_done (SnapType snaptype)
3518 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3520 ract->set_active ();
3525 Editor::snap_mode_selection_done (SnapMode mode)
3527 RefPtr<RadioAction> ract = snap_mode_action (mode);
3530 ract->set_active (true);
3535 Editor::cycle_edit_point (bool with_marker)
3537 if(Profile->get_mixbus())
3538 with_marker = false;
3540 switch (_edit_point) {
3542 set_edit_point_preference (EditAtPlayhead);
3544 case EditAtPlayhead:
3546 set_edit_point_preference (EditAtSelectedMarker);
3548 set_edit_point_preference (EditAtMouse);
3551 case EditAtSelectedMarker:
3552 set_edit_point_preference (EditAtMouse);
3558 Editor::edit_point_selection_done (EditPoint ep)
3560 set_edit_point_preference ( ep );
3564 Editor::build_zoom_focus_menu ()
3566 using namespace Menu_Helpers;
3568 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3569 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3570 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3571 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3572 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3573 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3575 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3579 Editor::zoom_focus_selection_done ( ZoomFocus f )
3581 RefPtr<RadioAction> ract = zoom_focus_action (f);
3583 ract->set_active ();
3588 Editor::build_track_count_menu ()
3590 using namespace Menu_Helpers;
3592 if (!Profile->get_mixbus()) {
3593 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3594 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3595 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3596 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3597 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3598 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3599 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3600 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3601 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3602 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3603 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3604 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3605 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3607 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3608 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3609 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3610 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3611 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3612 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3613 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3614 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3615 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3616 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3618 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3619 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3620 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3621 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3622 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3623 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3624 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3625 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3626 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3627 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3628 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3633 Editor::set_zoom_preset (int64_t ms)
3636 temporal_zoom_session();
3640 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3641 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3645 Editor::set_visible_track_count (int32_t n)
3647 _visible_track_count = n;
3649 /* if the canvas hasn't really been allocated any size yet, just
3650 record the desired number of visible tracks and return. when canvas
3651 allocation happens, we will get called again and then we can do the
3655 if (_visible_canvas_height <= 1) {
3661 DisplaySuspender ds;
3663 if (_visible_track_count > 0) {
3664 h = trackviews_height() / _visible_track_count;
3665 std::ostringstream s;
3666 s << _visible_track_count;
3668 } else if (_visible_track_count == 0) {
3670 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3671 if ((*i)->marked_for_display()) {
3675 h = trackviews_height() / n;
3678 /* negative value means that the visible track count has
3679 been overridden by explicit track height changes.
3681 visible_tracks_selector.set_text (X_("*"));
3685 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3686 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3689 if (str != visible_tracks_selector.get_text()) {
3690 visible_tracks_selector.set_text (str);
3695 Editor::override_visible_track_count ()
3697 _visible_track_count = -1;
3698 visible_tracks_selector.set_text ( _("*") );
3702 Editor::edit_controls_button_release (GdkEventButton* ev)
3704 if (Keyboard::is_context_menu_event (ev)) {
3705 ARDOUR_UI::instance()->add_route (current_toplevel());
3706 } else if (ev->button == 1) {
3707 selection->clear_tracks ();
3714 Editor::mouse_select_button_release (GdkEventButton* ev)
3716 /* this handles just right-clicks */
3718 if (ev->button != 3) {
3726 Editor::set_zoom_focus (ZoomFocus f)
3728 string str = zoom_focus_strings[(int)f];
3730 if (str != zoom_focus_selector.get_text()) {
3731 zoom_focus_selector.set_text (str);
3734 if (zoom_focus != f) {
3741 Editor::cycle_zoom_focus ()
3743 switch (zoom_focus) {
3745 set_zoom_focus (ZoomFocusRight);
3747 case ZoomFocusRight:
3748 set_zoom_focus (ZoomFocusCenter);
3750 case ZoomFocusCenter:
3751 set_zoom_focus (ZoomFocusPlayhead);
3753 case ZoomFocusPlayhead:
3754 set_zoom_focus (ZoomFocusMouse);
3756 case ZoomFocusMouse:
3757 set_zoom_focus (ZoomFocusEdit);
3760 set_zoom_focus (ZoomFocusLeft);
3766 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3768 /* recover or initialize pane positions. do this here rather than earlier because
3769 we don't want the positions to change the child allocations, which they seem to do.
3775 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3784 XMLNode* geometry = find_named_node (*node, "geometry");
3786 if (which == static_cast<Paned*> (&edit_pane)) {
3788 if (done & Horizontal) {
3792 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3793 _notebook_shrunk = string_is_affirmative (prop->value ());
3796 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3797 /* initial allocation is 90% to canvas, 10% to notebook */
3798 pos = (int) floor (alloc.get_width() * 0.90f);
3799 snprintf (buf, sizeof(buf), "%d", pos);
3801 pos = atoi (prop->value());
3804 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3805 edit_pane.set_position (pos);
3808 done = (Pane) (done | Horizontal);
3810 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3812 if (done & Vertical) {
3816 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3817 /* initial allocation is 90% to canvas, 10% to summary */
3818 pos = (int) floor (alloc.get_height() * 0.90f);
3819 snprintf (buf, sizeof(buf), "%d", pos);
3822 pos = atoi (prop->value());
3825 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3826 editor_summary_pane.set_position (pos);
3829 done = (Pane) (done | Vertical);
3834 Editor::set_show_measures (bool yn)
3836 if (_show_measures != yn) {
3839 if ((_show_measures = yn) == true) {
3841 tempo_lines->show();
3844 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3845 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3847 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3848 draw_measures (begin, end);
3856 Editor::toggle_follow_playhead ()
3858 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3860 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3861 set_follow_playhead (tact->get_active());
3865 /** @param yn true to follow playhead, otherwise false.
3866 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3869 Editor::set_follow_playhead (bool yn, bool catch_up)
3871 if (_follow_playhead != yn) {
3872 if ((_follow_playhead = yn) == true && catch_up) {
3874 reset_x_origin_to_follow_playhead ();
3881 Editor::toggle_stationary_playhead ()
3883 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3885 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3886 set_stationary_playhead (tact->get_active());
3891 Editor::set_stationary_playhead (bool yn)
3893 if (_stationary_playhead != yn) {
3894 if ((_stationary_playhead = yn) == true) {
3896 // FIXME need a 3.0 equivalent of this 2.X call
3897 // update_current_screen ();
3904 Editor::playlist_selector () const
3906 return *_playlist_selector;
3910 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
3912 if (paste_count == 0) {
3913 /* don't bother calculating an offset that will be zero anyway */
3917 /* calculate basic unsnapped multi-paste offset */
3918 framecnt_t offset = paste_count * duration;
3920 /* snap offset so pos + offset is aligned to the grid */
3921 framepos_t offset_pos = pos + offset;
3922 snap_to(offset_pos, RoundUpMaybe);
3923 offset = offset_pos - pos;
3929 Editor::get_grid_beat_divisions(framepos_t position)
3931 switch (_snap_type) {
3932 case SnapToBeatDiv128: return 128;
3933 case SnapToBeatDiv64: return 64;
3934 case SnapToBeatDiv32: return 32;
3935 case SnapToBeatDiv28: return 28;
3936 case SnapToBeatDiv24: return 24;
3937 case SnapToBeatDiv20: return 20;
3938 case SnapToBeatDiv16: return 16;
3939 case SnapToBeatDiv14: return 14;
3940 case SnapToBeatDiv12: return 12;
3941 case SnapToBeatDiv10: return 10;
3942 case SnapToBeatDiv8: return 8;
3943 case SnapToBeatDiv7: return 7;
3944 case SnapToBeatDiv6: return 6;
3945 case SnapToBeatDiv5: return 5;
3946 case SnapToBeatDiv4: return 4;
3947 case SnapToBeatDiv3: return 3;
3948 case SnapToBeatDiv2: return 2;
3955 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3959 const unsigned divisions = get_grid_beat_divisions(position);
3961 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
3964 switch (_snap_type) {
3966 return Evoral::Beats(1.0);
3969 return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
3977 return Evoral::Beats();
3981 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3985 ret = nudge_clock->current_duration (pos);
3986 next = ret + 1; /* XXXX fix me */
3992 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3994 ArdourDialog dialog (_("Playlist Deletion"));
3995 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3996 "If it is kept, its audio files will not be cleaned.\n"
3997 "If it is deleted, audio files used by it alone will be cleaned."),
4000 dialog.set_position (WIN_POS_CENTER);
4001 dialog.get_vbox()->pack_start (label);
4005 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4006 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4007 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4008 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4009 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4011 // by default gtk uses the left most button
4012 keep->grab_focus ();
4014 switch (dialog.run ()) {
4016 /* keep this and all remaining ones */
4021 /* delete this and all others */
4025 case RESPONSE_ACCEPT:
4026 /* delete the playlist */
4030 case RESPONSE_REJECT:
4031 /* keep the playlist */
4043 Editor::audio_region_selection_covers (framepos_t where)
4045 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4046 if ((*a)->region()->covers (where)) {
4055 Editor::prepare_for_cleanup ()
4057 cut_buffer->clear_regions ();
4058 cut_buffer->clear_playlists ();
4060 selection->clear_regions ();
4061 selection->clear_playlists ();
4063 _regions->suspend_redisplay ();
4067 Editor::finish_cleanup ()
4069 _regions->resume_redisplay ();
4073 Editor::transport_loop_location()
4076 return _session->locations()->auto_loop_location();
4083 Editor::transport_punch_location()
4086 return _session->locations()->auto_punch_location();
4093 Editor::control_layout_scroll (GdkEventScroll* ev)
4095 /* Just forward to the normal canvas scroll method. The coordinate
4096 systems are different but since the canvas is always larger than the
4097 track headers, and aligned with the trackview area, this will work.
4099 In the not too distant future this layout is going away anyway and
4100 headers will be on the canvas.
4102 return canvas_scroll_event (ev, false);
4106 Editor::session_state_saved (string)
4109 _snapshots->redisplay ();
4113 Editor::maximise_editing_space ()
4119 Gtk::Window* toplevel = current_toplevel();
4122 toplevel->fullscreen ();
4128 Editor::restore_editing_space ()
4134 Gtk::Window* toplevel = current_toplevel();
4137 toplevel->unfullscreen();
4143 * Make new playlists for a given track and also any others that belong
4144 * to the same active route group with the `select' property.
4149 Editor::new_playlists (TimeAxisView* v)
4151 begin_reversible_command (_("new playlists"));
4152 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4153 _session->playlists->get (playlists);
4154 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4155 commit_reversible_command ();
4159 * Use a copy of the current playlist for a given track and also any others that belong
4160 * to the same active route group with the `select' property.
4165 Editor::copy_playlists (TimeAxisView* v)
4167 begin_reversible_command (_("copy playlists"));
4168 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4169 _session->playlists->get (playlists);
4170 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4171 commit_reversible_command ();
4174 /** Clear the current playlist for a given track and also any others that belong
4175 * to the same active route group with the `select' property.
4180 Editor::clear_playlists (TimeAxisView* v)
4182 begin_reversible_command (_("clear playlists"));
4183 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4184 _session->playlists->get (playlists);
4185 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4186 commit_reversible_command ();
4190 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4192 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4196 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4198 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4202 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4204 atv.clear_playlist ();
4208 Editor::get_y_origin () const
4210 return vertical_adjustment.get_value ();
4213 /** Queue up a change to the viewport x origin.
4214 * @param frame New x origin.
4217 Editor::reset_x_origin (framepos_t frame)
4219 pending_visual_change.add (VisualChange::TimeOrigin);
4220 pending_visual_change.time_origin = frame;
4221 ensure_visual_change_idle_handler ();
4225 Editor::reset_y_origin (double y)
4227 pending_visual_change.add (VisualChange::YOrigin);
4228 pending_visual_change.y_origin = y;
4229 ensure_visual_change_idle_handler ();
4233 Editor::reset_zoom (framecnt_t spp)
4235 if (spp == samples_per_pixel) {
4239 pending_visual_change.add (VisualChange::ZoomLevel);
4240 pending_visual_change.samples_per_pixel = spp;
4241 ensure_visual_change_idle_handler ();
4245 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4247 reset_x_origin (frame);
4250 if (!no_save_visual) {
4251 undo_visual_stack.push_back (current_visual_state(false));
4255 Editor::VisualState::VisualState (bool with_tracks)
4256 : gui_state (with_tracks ? new GUIObjectState : 0)
4260 Editor::VisualState::~VisualState ()
4265 Editor::VisualState*
4266 Editor::current_visual_state (bool with_tracks)
4268 VisualState* vs = new VisualState (with_tracks);
4269 vs->y_position = vertical_adjustment.get_value();
4270 vs->samples_per_pixel = samples_per_pixel;
4271 vs->leftmost_frame = leftmost_frame;
4272 vs->zoom_focus = zoom_focus;
4275 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4282 Editor::undo_visual_state ()
4284 if (undo_visual_stack.empty()) {
4288 VisualState* vs = undo_visual_stack.back();
4289 undo_visual_stack.pop_back();
4292 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4295 use_visual_state (*vs);
4300 Editor::redo_visual_state ()
4302 if (redo_visual_stack.empty()) {
4306 VisualState* vs = redo_visual_stack.back();
4307 redo_visual_stack.pop_back();
4309 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4310 // why do we check here?
4311 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4314 use_visual_state (*vs);
4319 Editor::swap_visual_state ()
4321 if (undo_visual_stack.empty()) {
4322 redo_visual_state ();
4324 undo_visual_state ();
4329 Editor::use_visual_state (VisualState& vs)
4331 PBD::Unwinder<bool> nsv (no_save_visual, true);
4332 DisplaySuspender ds;
4334 vertical_adjustment.set_value (vs.y_position);
4336 set_zoom_focus (vs.zoom_focus);
4337 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4340 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4342 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4343 (*i)->clear_property_cache();
4344 (*i)->reset_visual_state ();
4348 _routes->update_visibility ();
4351 /** This is the core function that controls the zoom level of the canvas. It is called
4352 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4353 * @param spp new number of samples per pixel
4356 Editor::set_samples_per_pixel (framecnt_t spp)
4362 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4363 const framecnt_t lots_of_pixels = 4000;
4365 /* if the zoom level is greater than what you'd get trying to display 3
4366 * days of audio on a really big screen, then it's too big.
4369 if (spp * lots_of_pixels > three_days) {
4373 samples_per_pixel = spp;
4376 tempo_lines->tempo_map_changed();
4379 bool const showing_time_selection = selection->time.length() > 0;
4381 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4382 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4383 (*i)->reshow_selection (selection->time);
4387 ZoomChanged (); /* EMIT_SIGNAL */
4389 ArdourCanvas::GtkCanvasViewport* c;
4391 c = get_track_canvas();
4393 c->canvas()->zoomed ();
4396 if (playhead_cursor) {
4397 playhead_cursor->set_position (playhead_cursor->current_frame ());
4400 refresh_location_display();
4401 _summary->set_overlays_dirty ();
4403 update_marker_labels ();
4409 Editor::queue_visual_videotimeline_update ()
4412 * pending_visual_change.add (VisualChange::VideoTimeline);
4413 * or maybe even more specific: which videotimeline-image
4414 * currently it calls update_video_timeline() to update
4415 * _all outdated_ images on the video-timeline.
4416 * see 'exposeimg()' in video_image_frame.cc
4418 ensure_visual_change_idle_handler ();
4422 Editor::ensure_visual_change_idle_handler ()
4424 if (pending_visual_change.idle_handler_id < 0) {
4425 // see comment in add_to_idle_resize above.
4426 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4427 pending_visual_change.being_handled = false;
4432 Editor::_idle_visual_changer (void* arg)
4434 return static_cast<Editor*>(arg)->idle_visual_changer ();
4438 Editor::idle_visual_changer ()
4440 /* set_horizontal_position() below (and maybe other calls) call
4441 gtk_main_iteration(), so it's possible that a signal will be handled
4442 half-way through this method. If this signal wants an
4443 idle_visual_changer we must schedule another one after this one, so
4444 mark the idle_handler_id as -1 here to allow that. Also make a note
4445 that we are doing the visual change, so that changes in response to
4446 super-rapid-screen-update can be dropped if we are still processing
4450 pending_visual_change.idle_handler_id = -1;
4451 pending_visual_change.being_handled = true;
4453 VisualChange vc = pending_visual_change;
4455 pending_visual_change.pending = (VisualChange::Type) 0;
4457 visual_changer (vc);
4459 pending_visual_change.being_handled = false;
4461 return 0; /* this is always a one-shot call */
4465 Editor::visual_changer (const VisualChange& vc)
4467 double const last_time_origin = horizontal_position ();
4469 if (vc.pending & VisualChange::ZoomLevel) {
4470 set_samples_per_pixel (vc.samples_per_pixel);
4472 compute_fixed_ruler_scale ();
4474 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4475 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4477 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4478 current_bbt_points_begin, current_bbt_points_end);
4479 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4480 current_bbt_points_begin, current_bbt_points_end);
4481 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4483 update_video_timeline();
4486 if (vc.pending & VisualChange::TimeOrigin) {
4487 set_horizontal_position (vc.time_origin / samples_per_pixel);
4490 if (vc.pending & VisualChange::YOrigin) {
4491 vertical_adjustment.set_value (vc.y_origin);
4494 if (last_time_origin == horizontal_position ()) {
4495 /* changed signal not emitted */
4496 update_fixed_rulers ();
4497 redisplay_tempo (true);
4500 if (!(vc.pending & VisualChange::ZoomLevel)) {
4501 update_video_timeline();
4504 _summary->set_overlays_dirty ();
4507 struct EditorOrderTimeAxisSorter {
4508 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4509 return a->order () < b->order ();
4514 Editor::sort_track_selection (TrackViewList& sel)
4516 EditorOrderTimeAxisSorter cmp;
4521 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4524 framepos_t where = 0;
4525 EditPoint ep = _edit_point;
4527 if (Profile->get_mixbus())
4528 if (ep == EditAtSelectedMarker)
4529 ep = EditAtPlayhead;
4531 if (from_outside_canvas && (ep == EditAtMouse)) {
4532 ep = EditAtPlayhead;
4533 } else if (from_context_menu && (ep == EditAtMouse)) {
4534 return canvas_event_sample (&context_click_event, 0, 0);
4537 if (entered_marker) {
4538 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4539 return entered_marker->position();
4542 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4543 ep = EditAtSelectedMarker;
4546 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4547 ep = EditAtPlayhead;
4551 case EditAtPlayhead:
4552 if (_dragging_playhead) {
4553 where = *_control_scroll_target;
4555 where = _session->audible_frame();
4557 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4560 case EditAtSelectedMarker:
4561 if (!selection->markers.empty()) {
4563 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4566 where = loc->start();
4570 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4578 if (!mouse_frame (where, ignored)) {
4579 /* XXX not right but what can we do ? */
4583 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4591 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4593 if (!_session) return;
4595 begin_reversible_command (cmd);
4599 if ((tll = transport_loop_location()) == 0) {
4600 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4601 XMLNode &before = _session->locations()->get_state();
4602 _session->locations()->add (loc, true);
4603 _session->set_auto_loop_location (loc);
4604 XMLNode &after = _session->locations()->get_state();
4605 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4607 XMLNode &before = tll->get_state();
4608 tll->set_hidden (false, this);
4609 tll->set (start, end);
4610 XMLNode &after = tll->get_state();
4611 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4614 commit_reversible_command ();
4618 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4620 if (!_session) return;
4622 begin_reversible_command (cmd);
4626 if ((tpl = transport_punch_location()) == 0) {
4627 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4628 XMLNode &before = _session->locations()->get_state();
4629 _session->locations()->add (loc, true);
4630 _session->set_auto_punch_location (loc);
4631 XMLNode &after = _session->locations()->get_state();
4632 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4634 XMLNode &before = tpl->get_state();
4635 tpl->set_hidden (false, this);
4636 tpl->set (start, end);
4637 XMLNode &after = tpl->get_state();
4638 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4641 commit_reversible_command ();
4644 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4645 * @param rs List to which found regions are added.
4646 * @param where Time to look at.
4647 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4650 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4652 const TrackViewList* tracks;
4655 tracks = &track_views;
4660 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4662 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4665 boost::shared_ptr<Track> tr;
4666 boost::shared_ptr<Playlist> pl;
4668 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4670 boost::shared_ptr<RegionList> regions = pl->regions_at (
4671 (framepos_t) floor ( (double) where * tr->speed()));
4673 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4674 RegionView* rv = rtv->view()->find_view (*i);
4685 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4687 const TrackViewList* tracks;
4690 tracks = &track_views;
4695 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4696 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4698 boost::shared_ptr<Track> tr;
4699 boost::shared_ptr<Playlist> pl;
4701 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4703 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4704 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4706 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4708 RegionView* rv = rtv->view()->find_view (*i);
4719 /** Get regions using the following method:
4721 * Make a region list using:
4722 * (a) any selected regions
4723 * (b) the intersection of any selected tracks and the edit point(*)
4724 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4726 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4728 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4732 Editor::get_regions_from_selection_and_edit_point ()
4734 RegionSelection regions;
4736 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4737 regions.add (entered_regionview);
4739 regions = selection->regions;
4742 if ( regions.empty() ) {
4743 TrackViewList tracks = selection->tracks;
4745 if (!tracks.empty()) {
4746 /* no region selected or entered, but some selected tracks:
4747 * act on all regions on the selected tracks at the edit point
4749 framepos_t const where = get_preferred_edit_position ();
4750 get_regions_at(regions, where, tracks);
4757 /** Get regions using the following method:
4759 * Make a region list using:
4760 * (a) any selected regions
4761 * (b) the intersection of any selected tracks and the edit point(*)
4762 * (c) if neither exists, then whatever region is under the mouse
4764 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4766 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4769 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4771 RegionSelection regions;
4773 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4774 regions.add (entered_regionview);
4776 regions = selection->regions;
4779 if ( regions.empty() ) {
4780 TrackViewList tracks = selection->tracks;
4782 if (!tracks.empty()) {
4783 /* no region selected or entered, but some selected tracks:
4784 * act on all regions on the selected tracks at the edit point
4786 get_regions_at(regions, pos, tracks);
4793 /** Start with regions that are selected, or the entered regionview if none are selected.
4794 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4795 * of the regions that we started with.
4799 Editor::get_regions_from_selection_and_entered ()
4801 RegionSelection regions = selection->regions;
4803 if (regions.empty() && entered_regionview) {
4804 regions.add (entered_regionview);
4811 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4813 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4814 RouteTimeAxisView* rtav;
4816 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4817 boost::shared_ptr<Playlist> pl;
4818 std::vector<boost::shared_ptr<Region> > results;
4819 boost::shared_ptr<Track> tr;
4821 if ((tr = rtav->track()) == 0) {
4826 if ((pl = (tr->playlist())) != 0) {
4827 boost::shared_ptr<Region> r = pl->region_by_id (id);
4829 RegionView* rv = rtav->view()->find_view (r);
4831 regions.push_back (rv);
4840 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4843 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4844 MidiTimeAxisView* mtav;
4846 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4848 mtav->get_per_region_note_selection (selection);
4855 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4857 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4859 RouteTimeAxisView* tatv;
4861 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4863 boost::shared_ptr<Playlist> pl;
4864 vector<boost::shared_ptr<Region> > results;
4866 boost::shared_ptr<Track> tr;
4868 if ((tr = tatv->track()) == 0) {
4873 if ((pl = (tr->playlist())) != 0) {
4874 if (src_comparison) {
4875 pl->get_source_equivalent_regions (region, results);
4877 pl->get_region_list_equivalent_regions (region, results);
4881 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4882 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4883 regions.push_back (marv);
4892 Editor::show_rhythm_ferret ()
4894 if (rhythm_ferret == 0) {
4895 rhythm_ferret = new RhythmFerret(*this);
4898 rhythm_ferret->set_session (_session);
4899 rhythm_ferret->show ();
4900 rhythm_ferret->present ();
4904 Editor::first_idle ()
4906 MessageDialog* dialog = 0;
4908 if (track_views.size() > 1) {
4909 Timers::TimerSuspender t;
4910 dialog = new MessageDialog (
4911 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4915 ARDOUR_UI::instance()->flush_pending ();
4918 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4922 // first idle adds route children (automation tracks), so we need to redisplay here
4923 _routes->redisplay ();
4927 if (_session->undo_depth() == 0) {
4928 undo_action->set_sensitive(false);
4930 redo_action->set_sensitive(false);
4931 begin_selection_op_history ();
4937 Editor::_idle_resize (gpointer arg)
4939 return ((Editor*)arg)->idle_resize ();
4943 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4945 if (resize_idle_id < 0) {
4946 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
4947 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
4948 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
4950 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
4951 _pending_resize_amount = 0;
4954 /* make a note of the smallest resulting height, so that we can clamp the
4955 lower limit at TimeAxisView::hSmall */
4957 int32_t min_resulting = INT32_MAX;
4959 _pending_resize_amount += h;
4960 _pending_resize_view = view;
4962 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4964 if (selection->tracks.contains (_pending_resize_view)) {
4965 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4966 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4970 if (min_resulting < 0) {
4975 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4976 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4980 /** Handle pending resizing of tracks */
4982 Editor::idle_resize ()
4984 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4986 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4987 selection->tracks.contains (_pending_resize_view)) {
4989 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4990 if (*i != _pending_resize_view) {
4991 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4996 _pending_resize_amount = 0;
4997 _group_tabs->set_dirty ();
4998 resize_idle_id = -1;
5006 ENSURE_GUI_THREAD (*this, &Editor::located);
5009 playhead_cursor->set_position (_session->audible_frame ());
5010 if (_follow_playhead && !_pending_initial_locate) {
5011 reset_x_origin_to_follow_playhead ();
5015 _pending_locate_request = false;
5016 _pending_initial_locate = false;
5020 Editor::region_view_added (RegionView * rv)
5022 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5023 if (rv->region ()->id () == (*pr)) {
5024 selection->add (rv);
5025 selection->regions.pending.erase (pr);
5030 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5032 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5033 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5034 if (rv->region()->id () == (*rnote).first) {
5035 mrv->select_notes ((*rnote).second);
5036 selection->pending_midi_note_selection.erase(rnote);
5042 _summary->set_background_dirty ();
5046 Editor::region_view_removed ()
5048 _summary->set_background_dirty ();
5052 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5054 TrackViewList::const_iterator j = track_views.begin ();
5055 while (j != track_views.end()) {
5056 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5057 if (rtv && rtv->route() == r) {
5068 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5072 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5073 TimeAxisView* tv = axis_view_from_route (*i);
5083 Editor::suspend_route_redisplay ()
5086 _routes->suspend_redisplay();
5091 Editor::resume_route_redisplay ()
5094 _routes->redisplay(); // queue redisplay
5095 _routes->resume_redisplay();
5100 Editor::add_routes (RouteList& routes)
5102 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5104 RouteTimeAxisView *rtv;
5105 list<RouteTimeAxisView*> new_views;
5106 TrackViewList new_selection;
5107 bool from_scratch = (track_views.size() == 0);
5109 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5110 boost::shared_ptr<Route> route = (*x);
5112 if (route->is_auditioner() || route->is_monitor()) {
5116 DataType dt = route->input()->default_type();
5118 if (dt == ARDOUR::DataType::AUDIO) {
5119 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5120 rtv->set_route (route);
5121 } else if (dt == ARDOUR::DataType::MIDI) {
5122 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5123 rtv->set_route (route);
5125 throw unknown_type();
5128 new_views.push_back (rtv);
5129 track_views.push_back (rtv);
5130 new_selection.push_back (rtv);
5132 rtv->effective_gain_display ();
5134 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5135 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5138 if (new_views.size() > 0) {
5139 _routes->routes_added (new_views);
5140 _summary->routes_added (new_views);
5143 if (!from_scratch) {
5144 selection->tracks.clear();
5145 selection->add (new_selection);
5146 begin_selection_op_history();
5149 if (show_editor_mixer_when_tracks_arrive) {
5150 show_editor_mixer (true);
5153 editor_list_button.set_sensitive (true);
5157 Editor::timeaxisview_deleted (TimeAxisView *tv)
5159 if (tv == entered_track) {
5163 if (_session && _session->deletion_in_progress()) {
5164 /* the situation is under control */
5168 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5170 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5172 _routes->route_removed (tv);
5174 TimeAxisView::Children c = tv->get_child_list ();
5175 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5176 if (entered_track == i->get()) {
5181 /* remove it from the list of track views */
5183 TrackViewList::iterator i;
5185 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5186 i = track_views.erase (i);
5189 /* update whatever the current mixer strip is displaying, if revelant */
5191 boost::shared_ptr<Route> route;
5194 route = rtav->route ();
5197 if (current_mixer_strip && current_mixer_strip->route() == route) {
5199 TimeAxisView* next_tv;
5201 if (track_views.empty()) {
5203 } else if (i == track_views.end()) {
5204 next_tv = track_views.front();
5211 set_selected_mixer_strip (*next_tv);
5213 /* make the editor mixer strip go away setting the
5214 * button to inactive (which also unticks the menu option)
5217 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5223 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5225 if (apply_to_selection) {
5226 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5228 TrackSelection::iterator j = i;
5231 hide_track_in_display (*i, false);
5236 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5238 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5239 // this will hide the mixer strip
5240 set_selected_mixer_strip (*tv);
5243 _routes->hide_track_in_display (*tv);
5248 Editor::sync_track_view_list_and_routes ()
5250 track_views = TrackViewList (_routes->views ());
5252 _summary->set_background_dirty();
5253 _group_tabs->set_dirty ();
5255 return false; // do not call again (until needed)
5259 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5261 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5266 /** Find a RouteTimeAxisView by the ID of its route */
5268 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5270 RouteTimeAxisView* v;
5272 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5273 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5274 if(v->route()->id() == id) {
5284 Editor::fit_route_group (RouteGroup *g)
5286 TrackViewList ts = axis_views_from_routes (g->route_list ());
5291 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5293 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5296 _session->cancel_audition ();
5300 if (_session->is_auditioning()) {
5301 _session->cancel_audition ();
5302 if (r == last_audition_region) {
5307 _session->audition_region (r);
5308 last_audition_region = r;
5313 Editor::hide_a_region (boost::shared_ptr<Region> r)
5315 r->set_hidden (true);
5319 Editor::show_a_region (boost::shared_ptr<Region> r)
5321 r->set_hidden (false);
5325 Editor::audition_region_from_region_list ()
5327 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5331 Editor::hide_region_from_region_list ()
5333 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5337 Editor::show_region_in_region_list ()
5339 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5343 Editor::step_edit_status_change (bool yn)
5346 start_step_editing ();
5348 stop_step_editing ();
5353 Editor::start_step_editing ()
5355 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5359 Editor::stop_step_editing ()
5361 step_edit_connection.disconnect ();
5365 Editor::check_step_edit ()
5367 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5368 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5370 mtv->check_step_edit ();
5374 return true; // do it again, till we stop
5378 Editor::scroll_press (Direction dir)
5380 ++_scroll_callbacks;
5382 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5383 /* delay the first auto-repeat */
5389 scroll_backward (1);
5397 scroll_up_one_track ();
5401 scroll_down_one_track ();
5405 /* do hacky auto-repeat */
5406 if (!_scroll_connection.connected ()) {
5408 _scroll_connection = Glib::signal_timeout().connect (
5409 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5412 _scroll_callbacks = 0;
5419 Editor::scroll_release ()
5421 _scroll_connection.disconnect ();
5424 /** Queue a change for the Editor viewport x origin to follow the playhead */
5426 Editor::reset_x_origin_to_follow_playhead ()
5428 framepos_t const frame = playhead_cursor->current_frame ();
5430 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5432 if (_session->transport_speed() < 0) {
5434 if (frame > (current_page_samples() / 2)) {
5435 center_screen (frame-(current_page_samples()/2));
5437 center_screen (current_page_samples()/2);
5444 if (frame < leftmost_frame) {
5446 if (_session->transport_rolling()) {
5447 /* rolling; end up with the playhead at the right of the page */
5448 l = frame - current_page_samples ();
5450 /* not rolling: end up with the playhead 1/4 of the way along the page */
5451 l = frame - current_page_samples() / 4;
5455 if (_session->transport_rolling()) {
5456 /* rolling: end up with the playhead on the left of the page */
5459 /* not rolling: end up with the playhead 3/4 of the way along the page */
5460 l = frame - 3 * current_page_samples() / 4;
5468 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5474 Editor::super_rapid_screen_update ()
5476 if (!_session || !_session->engine().running()) {
5480 /* METERING / MIXER STRIPS */
5482 /* update track meters, if required */
5483 if (contents().is_mapped() && meters_running) {
5484 RouteTimeAxisView* rtv;
5485 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5486 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5487 rtv->fast_update ();
5492 /* and any current mixer strip */
5493 if (current_mixer_strip) {
5494 current_mixer_strip->fast_update ();
5497 /* PLAYHEAD AND VIEWPORT */
5499 framepos_t const frame = _session->audible_frame();
5501 /* There are a few reasons why we might not update the playhead / viewport stuff:
5503 * 1. we don't update things when there's a pending locate request, otherwise
5504 * when the editor requests a locate there is a chance that this method
5505 * will move the playhead before the locate request is processed, causing
5507 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5508 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5511 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5513 last_update_frame = frame;
5515 if (!_dragging_playhead) {
5516 playhead_cursor->set_position (frame);
5519 if (!_stationary_playhead) {
5521 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5522 /* We only do this if we aren't already
5523 handling a visual change (ie if
5524 pending_visual_change.being_handled is
5525 false) so that these requests don't stack
5526 up there are too many of them to handle in
5529 reset_x_origin_to_follow_playhead ();
5534 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5535 framepos_t const frame = playhead_cursor->current_frame ();
5536 double target = ((double)frame - (double)current_page_samples()/2.0);
5537 if (target <= 0.0) {
5540 // compare to EditorCursor::set_position()
5541 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5542 double const new_pos = sample_to_pixel_unrounded (target);
5543 if (rint (new_pos) != rint (old_pos)) {
5544 reset_x_origin (pixel_to_sample (floor (new_pos)));
5555 Editor::session_going_away ()
5557 _have_idled = false;
5559 _session_connections.drop_connections ();
5561 super_rapid_screen_update_connection.disconnect ();
5563 selection->clear ();
5564 cut_buffer->clear ();
5566 clicked_regionview = 0;
5567 clicked_axisview = 0;
5568 clicked_routeview = 0;
5569 entered_regionview = 0;
5571 last_update_frame = 0;
5574 playhead_cursor->hide ();
5576 /* rip everything out of the list displays */
5580 _route_groups->clear ();
5582 /* do this first so that deleting a track doesn't reset cms to null
5583 and thus cause a leak.
5586 if (current_mixer_strip) {
5587 if (current_mixer_strip->get_parent() != 0) {
5588 global_hpacker.remove (*current_mixer_strip);
5590 delete current_mixer_strip;
5591 current_mixer_strip = 0;
5594 /* delete all trackviews */
5596 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5599 track_views.clear ();
5601 nudge_clock->set_session (0);
5603 editor_list_button.set_active(false);
5604 editor_list_button.set_sensitive(false);
5606 /* clear tempo/meter rulers */
5607 remove_metric_marks ();
5609 clear_marker_display ();
5611 stop_step_editing ();
5615 /* get rid of any existing editor mixer strip */
5617 WindowTitle title(Glib::get_application_name());
5618 title += _("Editor");
5620 own_window()->set_title (title.get_string());
5623 SessionHandlePtr::session_going_away ();
5628 Editor::show_editor_list (bool yn)
5631 _the_notebook.show ();
5633 _the_notebook.hide ();
5638 Editor::change_region_layering_order (bool from_context_menu)
5640 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5642 if (!clicked_routeview) {
5643 if (layering_order_editor) {
5644 layering_order_editor->hide ();
5649 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5655 boost::shared_ptr<Playlist> pl = track->playlist();
5661 if (layering_order_editor == 0) {
5662 layering_order_editor = new RegionLayeringOrderEditor (*this);
5665 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5666 layering_order_editor->maybe_present ();
5670 Editor::update_region_layering_order_editor ()
5672 if (layering_order_editor && layering_order_editor->is_visible ()) {
5673 change_region_layering_order (true);
5678 Editor::setup_fade_images ()
5680 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5681 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5682 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5683 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5684 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5686 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5687 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5688 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5689 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5690 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5692 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5693 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5694 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5695 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5696 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5698 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5699 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5700 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5701 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5702 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5706 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5708 Editor::action_menu_item (std::string const & name)
5710 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5713 return *manage (a->create_menu_item ());
5717 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5719 EventBox* b = manage (new EventBox);
5720 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5721 Label* l = manage (new Label (name));
5725 _the_notebook.append_page (widget, *b);
5729 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5731 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5732 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5735 if (ev->type == GDK_2BUTTON_PRESS) {
5737 /* double-click on a notebook tab shrinks or expands the notebook */
5739 if (_notebook_shrunk) {
5740 if (pre_notebook_shrink_pane_width) {
5741 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5743 _notebook_shrunk = false;
5745 pre_notebook_shrink_pane_width = edit_pane.get_position();
5747 /* this expands the LHS of the edit pane to cover the notebook
5748 PAGE but leaves the tabs visible.
5750 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5751 _notebook_shrunk = true;
5759 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5761 using namespace Menu_Helpers;
5763 MenuList& items = _control_point_context_menu.items ();
5766 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5767 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5768 if (!can_remove_control_point (item)) {
5769 items.back().set_sensitive (false);
5772 _control_point_context_menu.popup (event->button.button, event->button.time);
5776 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5778 using namespace Menu_Helpers;
5780 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5785 /* We need to get the selection here and pass it to the operations, since
5786 popping up the menu will cause a region leave event which clears
5787 entered_regionview. */
5789 MidiRegionView& mrv = note->region_view();
5790 const RegionSelection rs = get_regions_from_selection_and_entered ();
5791 const uint32_t sel_size = mrv.selection_size ();
5793 MenuList& items = _note_context_menu.items();
5797 items.push_back(MenuElem(_("Delete"),
5798 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5801 items.push_back(MenuElem(_("Edit..."),
5802 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5803 if (sel_size != 1) {
5804 items.back().set_sensitive (false);
5807 items.push_back(MenuElem(_("Transpose..."),
5808 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
5811 items.push_back(MenuElem(_("Legatize"),
5812 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5814 items.back().set_sensitive (false);
5817 items.push_back(MenuElem(_("Quantize..."),
5818 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5820 items.push_back(MenuElem(_("Remove Overlap"),
5821 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5823 items.back().set_sensitive (false);
5826 items.push_back(MenuElem(_("Transform..."),
5827 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5829 _note_context_menu.popup (event->button.button, event->button.time);
5833 Editor::zoom_vertical_modifier_released()
5835 _stepping_axis_view = 0;
5839 Editor::ui_parameter_changed (string parameter)
5841 if (parameter == "icon-set") {
5842 while (!_cursor_stack.empty()) {
5843 _cursor_stack.pop_back();
5845 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
5846 _cursor_stack.push_back(_cursors->grabber);
5847 } else if (parameter == "draggable-playhead") {
5848 if (_verbose_cursor) {
5849 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
5855 Editor::use_own_window (bool and_fill_it)
5857 bool new_window = !own_window();
5859 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
5861 if (win && new_window) {
5862 win->set_name ("EditorWindow");
5864 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
5866 // win->signal_realize().connect (*this, &Editor::on_realize);
5867 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
5868 win->set_data ("ardour-bindings", &key_bindings);
5873 DisplaySuspender ds;
5874 contents().show_all ();
5876 /* XXX: this is a bit unfortunate; it would probably
5877 be nicer if we could just call show () above rather
5878 than needing the show_all ()
5881 /* re-hide stuff if necessary */
5882 editor_list_button_toggled ();
5883 parameter_changed ("show-summary");
5884 parameter_changed ("show-group-tabs");
5885 parameter_changed ("show-zoom-tools");
5887 /* now reset all audio_time_axis heights, because widgets might need
5893 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5894 tv = (static_cast<TimeAxisView*>(*i));
5895 tv->reset_height ();
5898 if (current_mixer_strip) {
5899 current_mixer_strip->hide_things ();
5900 current_mixer_strip->parameter_changed ("mixer-element-visibility");