2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include <gtkmm2ext/keyboard.h>
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
68 #include "ardour/analysis_graph.h"
69 #include "ardour/audio_track.h"
70 #include "ardour/audioengine.h"
71 #include "ardour/audioregion.h"
72 #include "ardour/lmath.h"
73 #include "ardour/location.h"
74 #include "ardour/profile.h"
75 #include "ardour/route_group.h"
76 #include "ardour/session_playlists.h"
77 #include "ardour/tempo.h"
78 #include "ardour/utils.h"
80 #include "canvas/debug.h"
81 #include "canvas/text.h"
83 #include "control_protocol/control_protocol.h"
86 #include "analysis_window.h"
87 #include "audio_clock.h"
88 #include "audio_region_view.h"
89 #include "audio_streamview.h"
90 #include "audio_time_axis.h"
91 #include "automation_time_axis.h"
92 #include "bundle_manager.h"
93 #include "crossfade_edit.h"
97 #include "editor_cursors.h"
98 #include "editor_drag.h"
99 #include "editor_group_tabs.h"
100 #include "editor_locations.h"
101 #include "editor_regions.h"
102 #include "editor_route_groups.h"
103 #include "editor_routes.h"
104 #include "editor_snapshots.h"
105 #include "editor_summary.h"
106 #include "export_report.h"
107 #include "global_port_matrix.h"
108 #include "gui_object.h"
109 #include "gui_thread.h"
110 #include "keyboard.h"
111 #include "keyeditor.h"
112 #include "luainstance.h"
114 #include "midi_region_view.h"
115 #include "midi_time_axis.h"
116 #include "mixer_strip.h"
117 #include "mixer_ui.h"
118 #include "mouse_cursors.h"
119 #include "note_base.h"
120 #include "playlist_selector.h"
121 #include "public_editor.h"
122 #include "quantize_dialog.h"
123 #include "region_layering_order_editor.h"
124 #include "rgb_macros.h"
125 #include "rhythm_ferret.h"
126 #include "selection.h"
127 #include "simple_progress_dialog.h"
129 #include "tempo_lines.h"
130 #include "time_axis_view.h"
132 #include "tooltips.h"
133 #include "ui_config.h"
135 #include "verbose_cursor.h"
140 using namespace ARDOUR;
141 using namespace ARDOUR_UI_UTILS;
144 using namespace Glib;
145 using namespace Gtkmm2ext;
146 using namespace Editing;
148 using PBD::internationalize;
150 using Gtkmm2ext::Keyboard;
152 double Editor::timebar_height = 15.0;
154 static const gchar *_snap_type_strings[] = {
188 static const gchar *_snap_mode_strings[] = {
195 static const gchar *_edit_point_strings[] = {
202 static const gchar *_edit_mode_strings[] = {
210 static const gchar *_zoom_focus_strings[] = {
220 #ifdef USE_RUBBERBAND
221 static const gchar *_rb_opt_strings[] = {
224 N_("Balanced multitimbral mixture"),
225 N_("Unpitched percussion with stable notes"),
226 N_("Crisp monophonic instrumental"),
227 N_("Unpitched solo percussion"),
228 N_("Resample without preserving pitch"),
233 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
236 pane_size_watcher (Paned* pane)
238 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
242 Quartz: impossible to access
244 so stop that by preventing it from ever getting too narrow. 35
245 pixels is basically a rough guess at the tab width.
250 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
252 gint pos = pane->get_position ();
254 if (pos > max_width_of_lhs) {
255 pane->set_position (max_width_of_lhs);
260 : PublicEditor (global_hpacker)
261 , editor_mixer_strip_width (Wide)
262 , constructed (false)
263 , _playlist_selector (0)
264 , no_save_visual (false)
266 , samples_per_pixel (2048)
267 , zoom_focus (ZoomFocusPlayhead)
268 , mouse_mode (MouseObject)
269 , pre_internal_snap_type (SnapToBeat)
270 , pre_internal_snap_mode (SnapOff)
271 , internal_snap_type (SnapToBeat)
272 , internal_snap_mode (SnapOff)
273 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
274 , _notebook_shrunk (false)
275 , location_marker_color (0)
276 , location_range_color (0)
277 , location_loop_color (0)
278 , location_punch_color (0)
279 , location_cd_marker_color (0)
281 , _show_marker_lines (false)
282 , clicked_axisview (0)
283 , clicked_routeview (0)
284 , clicked_regionview (0)
285 , clicked_selection (0)
286 , clicked_control_point (0)
287 , button_release_can_deselect (true)
288 , _mouse_changed_selection (false)
289 , region_edit_menu_split_item (0)
290 , region_edit_menu_split_multichannel_item (0)
291 , track_region_edit_playlist_menu (0)
292 , track_edit_playlist_submenu (0)
293 , track_selection_edit_playlist_submenu (0)
294 , _popup_region_menu_item (0)
296 , _track_canvas_viewport (0)
297 , within_track_canvas (false)
298 , _verbose_cursor (0)
302 , range_marker_group (0)
303 , transport_marker_group (0)
304 , cd_marker_group (0)
305 , _time_markers_group (0)
306 , hv_scroll_group (0)
308 , cursor_scroll_group (0)
309 , no_scroll_group (0)
310 , _trackview_group (0)
311 , _drag_motion_group (0)
312 , _canvas_drop_zone (0)
313 , no_ruler_shown_update (false)
314 , ruler_grabbed_widget (0)
316 , minsec_mark_interval (0)
317 , minsec_mark_modulo (0)
319 , timecode_mark_modulo (0)
320 , timecode_nmarks (0)
321 , _samples_ruler_interval (0)
324 , bbt_bar_helper_on (0)
325 , bbt_accent_modulo (0)
330 , visible_timebars (0)
331 , editor_ruler_menu (0)
335 , range_marker_bar (0)
336 , transport_marker_bar (0)
338 , minsec_label (_("Mins:Secs"))
339 , bbt_label (_("Bars:Beats"))
340 , timecode_label (_("Timecode"))
341 , samples_label (_("Samples"))
342 , tempo_label (_("Tempo"))
343 , meter_label (_("Meter"))
344 , mark_label (_("Location Markers"))
345 , range_mark_label (_("Range Markers"))
346 , transport_mark_label (_("Loop/Punch Ranges"))
347 , cd_mark_label (_("CD Markers"))
348 , videotl_label (_("Video Timeline"))
350 , playhead_cursor (0)
351 , edit_packer (4, 4, true)
352 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
353 , horizontal_adjustment (0.0, 0.0, 1e16)
354 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
355 , controls_layout (unused_adjustment, vertical_adjustment)
356 , _scroll_callbacks (0)
357 , _visible_canvas_width (0)
358 , _visible_canvas_height (0)
359 , _full_canvas_height (0)
360 , edit_controls_left_menu (0)
361 , edit_controls_right_menu (0)
362 , last_update_frame (0)
363 , cut_buffer_start (0)
364 , cut_buffer_length (0)
365 , button_bindings (0)
369 , current_interthread_info (0)
370 , analysis_window (0)
371 , select_new_marker (false)
373 , scrubbing_direction (0)
374 , scrub_reversals (0)
375 , scrub_reverse_distance (0)
376 , have_pending_keyboard_selection (false)
377 , pending_keyboard_selection_start (0)
378 , _snap_type (SnapToBeat)
379 , _snap_mode (SnapOff)
380 , snap_threshold (5.0)
381 , ignore_gui_changes (false)
382 , _drags (new DragManager (this))
384 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
385 , _dragging_playhead (false)
386 , _dragging_edit_point (false)
387 , _show_measures (true)
388 , _follow_playhead (true)
389 , _stationary_playhead (false)
392 , global_rect_group (0)
393 , time_line_group (0)
394 , tempo_or_meter_marker_menu (0)
396 , range_marker_menu (0)
397 , transport_marker_menu (0)
398 , new_transport_marker_menu (0)
400 , marker_menu_item (0)
401 , bbt_beat_subdivision (4)
402 , _visible_track_count (-1)
403 , toolbar_selection_clock_table (2,3)
404 , automation_mode_button (_("mode"))
405 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
406 , selection (new Selection (this))
407 , cut_buffer (new Selection (this))
408 , _selection_memento (new SelectionMemento())
409 , _all_region_actions_sensitized (false)
410 , _ignore_region_action (false)
411 , _last_region_menu_was_main (false)
412 , _ignore_follow_edits (false)
413 , cd_marker_bar_drag_rect (0)
414 , range_bar_drag_rect (0)
415 , transport_bar_drag_rect (0)
416 , transport_bar_range_rect (0)
417 , transport_bar_preroll_rect (0)
418 , transport_bar_postroll_rect (0)
419 , transport_loop_range_rect (0)
420 , transport_punch_range_rect (0)
421 , transport_punchin_line (0)
422 , transport_punchout_line (0)
423 , transport_preroll_rect (0)
424 , transport_postroll_rect (0)
426 , rubberband_rect (0)
432 , autoscroll_horizontal_allowed (false)
433 , autoscroll_vertical_allowed (false)
435 , autoscroll_widget (0)
436 , show_gain_after_trim (false)
437 , selection_op_cmd_depth (0)
438 , selection_op_history_it (0)
439 , no_save_instant (false)
441 , current_mixer_strip (0)
442 , show_editor_mixer_when_tracks_arrive (false)
443 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
444 , current_stepping_trackview (0)
445 , last_track_height_step_timestamp (0)
447 , entered_regionview (0)
448 , clear_entered_track (false)
449 , _edit_point (EditAtMouse)
450 , meters_running (false)
452 , _have_idled (false)
453 , resize_idle_id (-1)
454 , _pending_resize_amount (0)
455 , _pending_resize_view (0)
456 , _pending_locate_request (false)
457 , _pending_initial_locate (false)
461 , layering_order_editor (0)
462 , _last_cut_copy_source_track (0)
463 , _region_selection_change_updates_region_list (true)
465 , _following_mixer_selection (false)
466 , _control_point_toggled_on_press (false)
467 , _stepping_axis_view (0)
468 , quantize_dialog (0)
469 , _main_menu_disabler (0)
470 , myactions (X_("editor"))
472 /* we are a singleton */
474 PublicEditor::_instance = this;
478 last_event_time.tv_sec = 0;
479 last_event_time.tv_usec = 0;
481 selection_op_history.clear();
484 snap_type_strings = I18N (_snap_type_strings);
485 snap_mode_strings = I18N (_snap_mode_strings);
486 zoom_focus_strings = I18N (_zoom_focus_strings);
487 edit_mode_strings = I18N (_edit_mode_strings);
488 edit_point_strings = I18N (_edit_point_strings);
489 #ifdef USE_RUBBERBAND
490 rb_opt_strings = I18N (_rb_opt_strings);
494 build_edit_mode_menu();
495 build_zoom_focus_menu();
496 build_track_count_menu();
497 build_snap_mode_menu();
498 build_snap_type_menu();
499 build_edit_point_menu();
501 location_marker_color = UIConfiguration::instance().color ("location marker");
502 location_range_color = UIConfiguration::instance().color ("location range");
503 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
504 location_loop_color = UIConfiguration::instance().color ("location loop");
505 location_punch_color = UIConfiguration::instance().color ("location punch");
507 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
509 TimeAxisView::setup_sizes ();
510 ArdourMarker::setup_sizes (timebar_height);
512 bbt_label.set_name ("EditorRulerLabel");
513 bbt_label.set_size_request (-1, (int)timebar_height);
514 bbt_label.set_alignment (1.0, 0.5);
515 bbt_label.set_padding (5,0);
517 bbt_label.set_no_show_all();
518 minsec_label.set_name ("EditorRulerLabel");
519 minsec_label.set_size_request (-1, (int)timebar_height);
520 minsec_label.set_alignment (1.0, 0.5);
521 minsec_label.set_padding (5,0);
522 minsec_label.hide ();
523 minsec_label.set_no_show_all();
524 timecode_label.set_name ("EditorRulerLabel");
525 timecode_label.set_size_request (-1, (int)timebar_height);
526 timecode_label.set_alignment (1.0, 0.5);
527 timecode_label.set_padding (5,0);
528 timecode_label.hide ();
529 timecode_label.set_no_show_all();
530 samples_label.set_name ("EditorRulerLabel");
531 samples_label.set_size_request (-1, (int)timebar_height);
532 samples_label.set_alignment (1.0, 0.5);
533 samples_label.set_padding (5,0);
534 samples_label.hide ();
535 samples_label.set_no_show_all();
537 tempo_label.set_name ("EditorRulerLabel");
538 tempo_label.set_size_request (-1, (int)timebar_height);
539 tempo_label.set_alignment (1.0, 0.5);
540 tempo_label.set_padding (5,0);
542 tempo_label.set_no_show_all();
544 meter_label.set_name ("EditorRulerLabel");
545 meter_label.set_size_request (-1, (int)timebar_height);
546 meter_label.set_alignment (1.0, 0.5);
547 meter_label.set_padding (5,0);
549 meter_label.set_no_show_all();
551 if (Profile->get_trx()) {
552 mark_label.set_text (_("Markers"));
554 mark_label.set_name ("EditorRulerLabel");
555 mark_label.set_size_request (-1, (int)timebar_height);
556 mark_label.set_alignment (1.0, 0.5);
557 mark_label.set_padding (5,0);
559 mark_label.set_no_show_all();
561 cd_mark_label.set_name ("EditorRulerLabel");
562 cd_mark_label.set_size_request (-1, (int)timebar_height);
563 cd_mark_label.set_alignment (1.0, 0.5);
564 cd_mark_label.set_padding (5,0);
565 cd_mark_label.hide();
566 cd_mark_label.set_no_show_all();
568 videotl_bar_height = 4;
569 videotl_label.set_name ("EditorRulerLabel");
570 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
571 videotl_label.set_alignment (1.0, 0.5);
572 videotl_label.set_padding (5,0);
573 videotl_label.hide();
574 videotl_label.set_no_show_all();
576 range_mark_label.set_name ("EditorRulerLabel");
577 range_mark_label.set_size_request (-1, (int)timebar_height);
578 range_mark_label.set_alignment (1.0, 0.5);
579 range_mark_label.set_padding (5,0);
580 range_mark_label.hide();
581 range_mark_label.set_no_show_all();
583 transport_mark_label.set_name ("EditorRulerLabel");
584 transport_mark_label.set_size_request (-1, (int)timebar_height);
585 transport_mark_label.set_alignment (1.0, 0.5);
586 transport_mark_label.set_padding (5,0);
587 transport_mark_label.hide();
588 transport_mark_label.set_no_show_all();
590 initialize_canvas ();
592 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
594 _summary = new EditorSummary (this);
596 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
597 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
599 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
601 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
602 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
604 edit_controls_vbox.set_spacing (0);
605 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
606 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
608 HBox* h = manage (new HBox);
609 _group_tabs = new EditorGroupTabs (this);
610 if (!ARDOUR::Profile->get_trx()) {
611 h->pack_start (*_group_tabs, PACK_SHRINK);
613 h->pack_start (edit_controls_vbox);
614 controls_layout.add (*h);
616 controls_layout.set_name ("EditControlsBase");
617 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
618 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
619 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
621 _cursors = new MouseCursors;
622 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
623 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
625 /* Push default cursor to ever-present bottom of cursor stack. */
626 push_canvas_cursor(_cursors->grabber);
628 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
630 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
631 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
632 pad_line_1->set_outline_color (0xFF0000FF);
638 edit_packer.set_col_spacings (0);
639 edit_packer.set_row_spacings (0);
640 edit_packer.set_homogeneous (false);
641 edit_packer.set_border_width (0);
642 edit_packer.set_name ("EditorWindow");
644 time_bars_event_box.add (time_bars_vbox);
645 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
646 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
648 /* labels for the time bars */
649 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
651 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
653 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
655 bottom_hbox.set_border_width (2);
656 bottom_hbox.set_spacing (3);
658 _route_groups = new EditorRouteGroups (this);
659 _routes = new EditorRoutes (this);
660 _regions = new EditorRegions (this);
661 _snapshots = new EditorSnapshots (this);
662 _locations = new EditorLocations (this);
664 /* these are static location signals */
666 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
667 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
668 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
670 add_notebook_page (_("Regions"), _regions->widget ());
671 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
672 add_notebook_page (_("Snapshots"), _snapshots->widget ());
673 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
674 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
676 _the_notebook.set_show_tabs (true);
677 _the_notebook.set_scrollable (true);
678 _the_notebook.popup_disable ();
679 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
680 _the_notebook.show_all ();
682 _notebook_shrunk = false;
684 editor_summary_pane.pack1(edit_packer);
686 Button* summary_arrows_left_left = manage (new Button);
687 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
688 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
689 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
691 Button* summary_arrows_left_right = manage (new Button);
692 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
693 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
694 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
696 VBox* summary_arrows_left = manage (new VBox);
697 summary_arrows_left->pack_start (*summary_arrows_left_left);
698 summary_arrows_left->pack_start (*summary_arrows_left_right);
700 Button* summary_arrows_right_up = manage (new Button);
701 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
702 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
703 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
705 Button* summary_arrows_right_down = manage (new Button);
706 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
707 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
708 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
710 VBox* summary_arrows_right = manage (new VBox);
711 summary_arrows_right->pack_start (*summary_arrows_right_up);
712 summary_arrows_right->pack_start (*summary_arrows_right_down);
714 Frame* summary_frame = manage (new Frame);
715 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
717 summary_frame->add (*_summary);
718 summary_frame->show ();
720 _summary_hbox.pack_start (*summary_arrows_left, false, false);
721 _summary_hbox.pack_start (*summary_frame, true, true);
722 _summary_hbox.pack_start (*summary_arrows_right, false, false);
724 if (!ARDOUR::Profile->get_trx()) {
725 editor_summary_pane.pack2 (_summary_hbox);
728 edit_pane.pack1 (editor_summary_pane, true, true);
729 if (!ARDOUR::Profile->get_trx()) {
730 edit_pane.pack2 (_the_notebook, false, true);
733 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
735 /* XXX: editor_summary_pane might need similar to the edit_pane */
737 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
739 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
740 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
742 top_hbox.pack_start (toolbar_frame);
744 HBox *hbox = manage (new HBox);
745 hbox->pack_start (edit_pane, true, true);
747 global_vpacker.pack_start (top_hbox, false, false);
748 global_vpacker.pack_start (*hbox, true, true);
749 global_hpacker.pack_start (global_vpacker, true, true);
751 /* need to show the "contents" widget so that notebook will show if tab is switched to
754 global_hpacker.show ();
756 /* register actions now so that set_state() can find them and set toggles/checks etc */
763 _playlist_selector = new PlaylistSelector();
764 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
766 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
770 nudge_forward_button.set_name ("nudge button");
771 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
773 nudge_backward_button.set_name ("nudge button");
774 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
776 fade_context_menu.set_name ("ArdourContextMenu");
778 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
780 /* allow external control surfaces/protocols to do various things */
782 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
783 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
784 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
785 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
786 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
787 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
788 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
789 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
790 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
791 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
792 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
793 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
794 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
795 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
797 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
798 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
799 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
800 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
801 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
803 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
805 /* problematic: has to return a value and thus cannot be x-thread */
807 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
809 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
810 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
812 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
814 _ignore_region_action = false;
815 _last_region_menu_was_main = false;
816 _popup_region_menu_item = 0;
818 _ignore_follow_edits = false;
820 _show_marker_lines = false;
822 /* Button bindings */
824 button_bindings = new Bindings ("editor-mouse");
826 XMLNode* node = button_settings();
828 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
829 button_bindings->load_operation (**i);
835 /* grab current parameter state */
836 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
837 UIConfiguration::instance().map_parameters (pc);
839 setup_fade_images ();
841 LuaInstance::instance(); // instantiate
842 LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &Editor::set_script_action_name));
849 delete button_bindings;
851 delete _route_groups;
852 delete _track_canvas_viewport;
855 delete quantize_dialog;
861 delete _playlist_selector;
863 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
869 Editor::button_settings () const
871 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
872 XMLNode* node = find_named_node (*settings, X_("Buttons"));
875 node = new XMLNode (X_("Buttons"));
882 Editor::get_smart_mode () const
884 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
888 Editor::catch_vanishing_regionview (RegionView *rv)
890 /* note: the selection will take care of the vanishing
891 audioregionview by itself.
894 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
898 if (clicked_regionview == rv) {
899 clicked_regionview = 0;
902 if (entered_regionview == rv) {
903 set_entered_regionview (0);
906 if (!_all_region_actions_sensitized) {
907 sensitize_all_region_actions (true);
912 Editor::set_entered_regionview (RegionView* rv)
914 if (rv == entered_regionview) {
918 if (entered_regionview) {
919 entered_regionview->exited ();
922 entered_regionview = rv;
924 if (entered_regionview != 0) {
925 entered_regionview->entered ();
928 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
929 /* This RegionView entry might have changed what region actions
930 are allowed, so sensitize them all in case a key is pressed.
932 sensitize_all_region_actions (true);
937 Editor::set_entered_track (TimeAxisView* tav)
940 entered_track->exited ();
946 entered_track->entered ();
951 Editor::instant_save ()
953 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
958 _session->add_instant_xml(get_state());
960 Config->add_instant_xml(get_state());
965 Editor::control_vertical_zoom_in_all ()
967 tav_zoom_smooth (false, true);
971 Editor::control_vertical_zoom_out_all ()
973 tav_zoom_smooth (true, true);
977 Editor::control_vertical_zoom_in_selected ()
979 tav_zoom_smooth (false, false);
983 Editor::control_vertical_zoom_out_selected ()
985 tav_zoom_smooth (true, false);
989 Editor::control_view (uint32_t view)
991 goto_visual_state (view);
995 Editor::control_unselect ()
997 selection->clear_tracks ();
1001 Editor::control_select (uint32_t rid, Selection::Operation op)
1003 /* handles the (static) signal from the ControlProtocol class that
1004 * requests setting the selected track to a given RID
1011 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1017 TimeAxisView* tav = axis_view_from_route (r);
1021 case Selection::Add:
1022 selection->add (tav);
1024 case Selection::Toggle:
1025 selection->toggle (tav);
1027 case Selection::Extend:
1029 case Selection::Set:
1030 selection->set (tav);
1034 selection->clear_tracks ();
1039 Editor::control_step_tracks_up ()
1041 scroll_tracks_up_line ();
1045 Editor::control_step_tracks_down ()
1047 scroll_tracks_down_line ();
1051 Editor::control_scroll (float fraction)
1053 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1059 double step = fraction * current_page_samples();
1062 _control_scroll_target is an optional<T>
1064 it acts like a pointer to an framepos_t, with
1065 a operator conversion to boolean to check
1066 that it has a value could possibly use
1067 playhead_cursor->current_frame to store the
1068 value and a boolean in the class to know
1069 when it's out of date
1072 if (!_control_scroll_target) {
1073 _control_scroll_target = _session->transport_frame();
1074 _dragging_playhead = true;
1077 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1078 *_control_scroll_target = 0;
1079 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1080 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1082 *_control_scroll_target += (framepos_t) trunc (step);
1085 /* move visuals, we'll catch up with it later */
1087 playhead_cursor->set_position (*_control_scroll_target);
1088 UpdateAllTransportClocks (*_control_scroll_target);
1090 if (*_control_scroll_target > (current_page_samples() / 2)) {
1091 /* try to center PH in window */
1092 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1098 Now we do a timeout to actually bring the session to the right place
1099 according to the playhead. This is to avoid reading disk buffers on every
1100 call to control_scroll, which is driven by ScrollTimeline and therefore
1101 probably by a control surface wheel which can generate lots of events.
1103 /* cancel the existing timeout */
1105 control_scroll_connection.disconnect ();
1107 /* add the next timeout */
1109 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1113 Editor::deferred_control_scroll (framepos_t /*target*/)
1115 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1116 // reset for next stream
1117 _control_scroll_target = boost::none;
1118 _dragging_playhead = false;
1123 Editor::access_action (std::string action_group, std::string action_item)
1129 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1132 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1140 Editor::on_realize ()
1144 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1145 start_lock_event_timing ();
1150 Editor::start_lock_event_timing ()
1152 /* check if we should lock the GUI every 30 seconds */
1154 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1158 Editor::generic_event_handler (GdkEvent* ev)
1161 case GDK_BUTTON_PRESS:
1162 case GDK_BUTTON_RELEASE:
1163 case GDK_MOTION_NOTIFY:
1165 case GDK_KEY_RELEASE:
1166 if (contents().is_mapped()) {
1167 gettimeofday (&last_event_time, 0);
1171 case GDK_LEAVE_NOTIFY:
1172 switch (ev->crossing.detail) {
1173 case GDK_NOTIFY_UNKNOWN:
1174 case GDK_NOTIFY_INFERIOR:
1175 case GDK_NOTIFY_ANCESTOR:
1177 case GDK_NOTIFY_VIRTUAL:
1178 case GDK_NOTIFY_NONLINEAR:
1179 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1180 /* leaving window, so reset focus, thus ending any and
1181 all text entry operations.
1183 reset_focus (&contents());
1196 Editor::lock_timeout_callback ()
1198 struct timeval now, delta;
1200 gettimeofday (&now, 0);
1202 timersub (&now, &last_event_time, &delta);
1204 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1206 /* don't call again. Returning false will effectively
1207 disconnect us from the timer callback.
1209 unlock() will call start_lock_event_timing() to get things
1219 Editor::map_position_change (framepos_t frame)
1221 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1223 if (_session == 0) {
1227 if (_follow_playhead) {
1228 center_screen (frame);
1231 playhead_cursor->set_position (frame);
1235 Editor::center_screen (framepos_t frame)
1237 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1239 /* if we're off the page, then scroll.
1242 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1243 center_screen_internal (frame, page);
1248 Editor::center_screen_internal (framepos_t frame, float page)
1253 frame -= (framepos_t) page;
1258 reset_x_origin (frame);
1263 Editor::update_title ()
1265 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1267 if (!own_window()) {
1272 bool dirty = _session->dirty();
1274 string session_name;
1276 if (_session->snap_name() != _session->name()) {
1277 session_name = _session->snap_name();
1279 session_name = _session->name();
1283 session_name = "*" + session_name;
1286 WindowTitle title(session_name);
1287 title += S_("Window|Editor");
1288 title += Glib::get_application_name();
1289 own_window()->set_title (title.get_string());
1291 /* ::session_going_away() will have taken care of it */
1296 Editor::set_session (Session *t)
1298 SessionHandlePtr::set_session (t);
1304 _playlist_selector->set_session (_session);
1305 nudge_clock->set_session (_session);
1306 _summary->set_session (_session);
1307 _group_tabs->set_session (_session);
1308 _route_groups->set_session (_session);
1309 _regions->set_session (_session);
1310 _snapshots->set_session (_session);
1311 _routes->set_session (_session);
1312 _locations->set_session (_session);
1314 if (rhythm_ferret) {
1315 rhythm_ferret->set_session (_session);
1318 if (analysis_window) {
1319 analysis_window->set_session (_session);
1323 sfbrowser->set_session (_session);
1326 compute_fixed_ruler_scale ();
1328 /* Make sure we have auto loop and auto punch ranges */
1330 Location* loc = _session->locations()->auto_loop_location();
1332 loc->set_name (_("Loop"));
1335 loc = _session->locations()->auto_punch_location();
1338 loc->set_name (_("Punch"));
1341 refresh_location_display ();
1343 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1344 the selected Marker; this needs the LocationMarker list to be available.
1346 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1347 set_state (*node, Stateful::loading_state_version);
1349 /* catch up with the playhead */
1351 _session->request_locate (playhead_cursor->current_frame ());
1352 _pending_initial_locate = true;
1356 /* These signals can all be emitted by a non-GUI thread. Therefore the
1357 handlers for them must not attempt to directly interact with the GUI,
1358 but use PBD::Signal<T>::connect() which accepts an event loop
1359 ("context") where the handler will be asked to run.
1362 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1363 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1364 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1365 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1366 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1367 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1368 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1369 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1370 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1371 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1372 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1373 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1374 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1376 playhead_cursor->show ();
1378 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1379 Config->map_parameters (pc);
1380 _session->config.map_parameters (pc);
1382 restore_ruler_visibility ();
1383 //tempo_map_changed (PropertyChange (0));
1384 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1386 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1387 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1390 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1391 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1394 switch (_snap_type) {
1395 case SnapToRegionStart:
1396 case SnapToRegionEnd:
1397 case SnapToRegionSync:
1398 case SnapToRegionBoundary:
1399 build_region_boundary_cache ();
1406 /* register for undo history */
1407 _session->register_with_memento_command_factory(id(), this);
1408 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1410 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1412 LuaInstance::instance()->set_session(_session);
1414 start_updating_meters ();
1418 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1420 if (a->get_name() == "RegionMenu") {
1421 /* When the main menu's region menu is opened, we setup the actions so that they look right
1422 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1423 so we resensitize all region actions when the entered regionview or the region selection
1424 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1425 happens after the region context menu is opened. So we set a flag here, too.
1429 sensitize_the_right_region_actions ();
1430 _last_region_menu_was_main = true;
1435 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1437 using namespace Menu_Helpers;
1439 void (Editor::*emf)(FadeShape);
1440 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1443 images = &_xfade_in_images;
1444 emf = &Editor::set_fade_in_shape;
1446 images = &_xfade_out_images;
1447 emf = &Editor::set_fade_out_shape;
1452 _("Linear (for highly correlated material)"),
1453 *(*images)[FadeLinear],
1454 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1458 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1462 _("Constant power"),
1463 *(*images)[FadeConstantPower],
1464 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1467 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1472 *(*images)[FadeSymmetric],
1473 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1477 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1482 *(*images)[FadeSlow],
1483 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1486 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1491 *(*images)[FadeFast],
1492 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1495 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1498 /** Pop up a context menu for when the user clicks on a start crossfade */
1500 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1502 using namespace Menu_Helpers;
1503 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1508 MenuList& items (xfade_in_context_menu.items());
1511 if (arv->audio_region()->fade_in_active()) {
1512 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1514 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1517 items.push_back (SeparatorElem());
1518 fill_xfade_menu (items, true);
1520 xfade_in_context_menu.popup (button, time);
1523 /** Pop up a context menu for when the user clicks on an end crossfade */
1525 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1527 using namespace Menu_Helpers;
1528 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1533 MenuList& items (xfade_out_context_menu.items());
1536 if (arv->audio_region()->fade_out_active()) {
1537 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1539 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1542 items.push_back (SeparatorElem());
1543 fill_xfade_menu (items, false);
1545 xfade_out_context_menu.popup (button, time);
1549 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1551 using namespace Menu_Helpers;
1552 Menu* (Editor::*build_menu_function)();
1555 switch (item_type) {
1557 case RegionViewName:
1558 case RegionViewNameHighlight:
1559 case LeftFrameHandle:
1560 case RightFrameHandle:
1561 if (with_selection) {
1562 build_menu_function = &Editor::build_track_selection_context_menu;
1564 build_menu_function = &Editor::build_track_region_context_menu;
1569 if (with_selection) {
1570 build_menu_function = &Editor::build_track_selection_context_menu;
1572 build_menu_function = &Editor::build_track_context_menu;
1577 if (clicked_routeview->track()) {
1578 build_menu_function = &Editor::build_track_context_menu;
1580 build_menu_function = &Editor::build_track_bus_context_menu;
1585 /* probably shouldn't happen but if it does, we don't care */
1589 menu = (this->*build_menu_function)();
1590 menu->set_name ("ArdourContextMenu");
1592 /* now handle specific situations */
1594 switch (item_type) {
1596 case RegionViewName:
1597 case RegionViewNameHighlight:
1598 case LeftFrameHandle:
1599 case RightFrameHandle:
1600 if (!with_selection) {
1601 if (region_edit_menu_split_item) {
1602 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1603 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1605 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1608 if (region_edit_menu_split_multichannel_item) {
1609 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1610 region_edit_menu_split_multichannel_item->set_sensitive (true);
1612 region_edit_menu_split_multichannel_item->set_sensitive (false);
1625 /* probably shouldn't happen but if it does, we don't care */
1629 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1631 /* Bounce to disk */
1633 using namespace Menu_Helpers;
1634 MenuList& edit_items = menu->items();
1636 edit_items.push_back (SeparatorElem());
1638 switch (clicked_routeview->audio_track()->freeze_state()) {
1639 case AudioTrack::NoFreeze:
1640 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1643 case AudioTrack::Frozen:
1644 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1647 case AudioTrack::UnFrozen:
1648 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1654 if (item_type == StreamItem && clicked_routeview) {
1655 clicked_routeview->build_underlay_menu(menu);
1658 /* When the region menu is opened, we setup the actions so that they look right
1661 sensitize_the_right_region_actions ();
1662 _last_region_menu_was_main = false;
1664 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1665 menu->popup (button, time);
1669 Editor::build_track_context_menu ()
1671 using namespace Menu_Helpers;
1673 MenuList& edit_items = track_context_menu.items();
1676 add_dstream_context_items (edit_items);
1677 return &track_context_menu;
1681 Editor::build_track_bus_context_menu ()
1683 using namespace Menu_Helpers;
1685 MenuList& edit_items = track_context_menu.items();
1688 add_bus_context_items (edit_items);
1689 return &track_context_menu;
1693 Editor::build_track_region_context_menu ()
1695 using namespace Menu_Helpers;
1696 MenuList& edit_items = track_region_context_menu.items();
1699 /* we've just cleared the track region context menu, so the menu that these
1700 two items were on will have disappeared; stop them dangling.
1702 region_edit_menu_split_item = 0;
1703 region_edit_menu_split_multichannel_item = 0;
1705 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1708 boost::shared_ptr<Track> tr;
1709 boost::shared_ptr<Playlist> pl;
1711 if ((tr = rtv->track())) {
1712 add_region_context_items (edit_items, tr);
1716 add_dstream_context_items (edit_items);
1718 return &track_region_context_menu;
1722 Editor::loudness_analyze_region_selection ()
1727 Selection& s (PublicEditor::instance ().get_selection ());
1728 RegionSelection ars = s.regions;
1729 ARDOUR::AnalysisGraph ag (_session);
1730 framecnt_t total_work = 0;
1732 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1733 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1737 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1740 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1741 total_work += arv->region ()->length ();
1744 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1746 ag.set_total_frames (total_work);
1747 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1750 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1751 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1755 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1759 ag.analyze_region (ar);
1762 if (!ag.canceled ()) {
1763 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1769 Editor::loudness_analyze_range_selection ()
1774 Selection& s (PublicEditor::instance ().get_selection ());
1775 TimeSelection ts = s.time;
1776 ARDOUR::AnalysisGraph ag (_session);
1777 framecnt_t total_work = 0;
1779 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1780 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1784 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1788 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1789 total_work += j->length ();
1793 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1795 ag.set_total_frames (total_work);
1796 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1799 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1800 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1804 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1808 ag.analyze_range (rui->route (), pl, ts);
1811 if (!ag.canceled ()) {
1812 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1818 Editor::spectral_analyze_region_selection ()
1820 if (analysis_window == 0) {
1821 analysis_window = new AnalysisWindow();
1824 analysis_window->set_session(_session);
1826 analysis_window->show_all();
1829 analysis_window->set_regionmode();
1830 analysis_window->analyze();
1832 analysis_window->present();
1836 Editor::spectral_analyze_range_selection()
1838 if (analysis_window == 0) {
1839 analysis_window = new AnalysisWindow();
1842 analysis_window->set_session(_session);
1844 analysis_window->show_all();
1847 analysis_window->set_rangemode();
1848 analysis_window->analyze();
1850 analysis_window->present();
1854 Editor::build_track_selection_context_menu ()
1856 using namespace Menu_Helpers;
1857 MenuList& edit_items = track_selection_context_menu.items();
1858 edit_items.clear ();
1860 add_selection_context_items (edit_items);
1861 // edit_items.push_back (SeparatorElem());
1862 // add_dstream_context_items (edit_items);
1864 return &track_selection_context_menu;
1868 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1870 using namespace Menu_Helpers;
1872 /* OK, stick the region submenu at the top of the list, and then add
1876 RegionSelection rs = get_regions_from_selection_and_entered ();
1878 string::size_type pos = 0;
1879 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1881 /* we have to hack up the region name because "_" has a special
1882 meaning for menu titles.
1885 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1886 menu_item_name.replace (pos, 1, "__");
1890 if (_popup_region_menu_item == 0) {
1891 _popup_region_menu_item = new MenuItem (menu_item_name);
1892 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1893 _popup_region_menu_item->show ();
1895 _popup_region_menu_item->set_label (menu_item_name);
1898 /* No latering allowed in later is higher layering model */
1899 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1900 if (act && Config->get_layer_model() == LaterHigher) {
1901 act->set_sensitive (false);
1903 act->set_sensitive (true);
1906 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1908 edit_items.push_back (*_popup_region_menu_item);
1909 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1910 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1912 edit_items.push_back (SeparatorElem());
1915 /** Add context menu items relevant to selection ranges.
1916 * @param edit_items List to add the items to.
1919 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1921 using namespace Menu_Helpers;
1923 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1924 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1926 edit_items.push_back (SeparatorElem());
1927 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1929 edit_items.push_back (SeparatorElem());
1930 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1931 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1933 edit_items.push_back (SeparatorElem());
1935 edit_items.push_back (
1937 _("Move Range Start to Previous Region Boundary"),
1938 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1942 edit_items.push_back (
1944 _("Move Range Start to Next Region Boundary"),
1945 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1949 edit_items.push_back (
1951 _("Move Range End to Previous Region Boundary"),
1952 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1956 edit_items.push_back (
1958 _("Move Range End to Next Region Boundary"),
1959 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1963 edit_items.push_back (SeparatorElem());
1964 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1965 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1967 edit_items.push_back (SeparatorElem());
1968 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1970 edit_items.push_back (SeparatorElem());
1971 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1972 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1973 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1975 edit_items.push_back (SeparatorElem());
1976 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1978 edit_items.push_back (SeparatorElem());
1979 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1980 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1982 edit_items.push_back (SeparatorElem());
1983 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1984 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1985 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1986 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1987 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1988 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1989 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1995 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1997 using namespace Menu_Helpers;
2001 Menu *play_menu = manage (new Menu);
2002 MenuList& play_items = play_menu->items();
2003 play_menu->set_name ("ArdourContextMenu");
2005 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2006 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2007 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2008 play_items.push_back (SeparatorElem());
2009 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2011 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2015 Menu *select_menu = manage (new Menu);
2016 MenuList& select_items = select_menu->items();
2017 select_menu->set_name ("ArdourContextMenu");
2019 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2020 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2021 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2022 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2023 select_items.push_back (SeparatorElem());
2024 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2025 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2026 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2027 select_items.push_back (SeparatorElem());
2028 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2029 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2030 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2031 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2032 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2033 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2034 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2036 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2040 Menu *cutnpaste_menu = manage (new Menu);
2041 MenuList& cutnpaste_items = cutnpaste_menu->items();
2042 cutnpaste_menu->set_name ("ArdourContextMenu");
2044 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2045 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2046 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2048 cutnpaste_items.push_back (SeparatorElem());
2050 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2051 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2053 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2055 /* Adding new material */
2057 edit_items.push_back (SeparatorElem());
2058 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2059 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2063 Menu *nudge_menu = manage (new Menu());
2064 MenuList& nudge_items = nudge_menu->items();
2065 nudge_menu->set_name ("ArdourContextMenu");
2067 edit_items.push_back (SeparatorElem());
2068 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2069 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2070 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2071 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2073 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2077 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2079 using namespace Menu_Helpers;
2083 Menu *play_menu = manage (new Menu);
2084 MenuList& play_items = play_menu->items();
2085 play_menu->set_name ("ArdourContextMenu");
2087 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2088 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2089 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2093 Menu *select_menu = manage (new Menu);
2094 MenuList& select_items = select_menu->items();
2095 select_menu->set_name ("ArdourContextMenu");
2097 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2098 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2099 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2100 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2101 select_items.push_back (SeparatorElem());
2102 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2103 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2104 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2105 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2107 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2111 Menu *cutnpaste_menu = manage (new Menu);
2112 MenuList& cutnpaste_items = cutnpaste_menu->items();
2113 cutnpaste_menu->set_name ("ArdourContextMenu");
2115 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2116 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2117 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2119 Menu *nudge_menu = manage (new Menu());
2120 MenuList& nudge_items = nudge_menu->items();
2121 nudge_menu->set_name ("ArdourContextMenu");
2123 edit_items.push_back (SeparatorElem());
2124 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2125 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2126 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2127 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2129 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2133 Editor::snap_type() const
2139 Editor::snap_mode() const
2145 Editor::set_snap_to (SnapType st)
2147 unsigned int snap_ind = (unsigned int)st;
2149 if (internal_editing()) {
2150 internal_snap_type = st;
2152 pre_internal_snap_type = st;
2157 if (snap_ind > snap_type_strings.size() - 1) {
2159 _snap_type = (SnapType)snap_ind;
2162 string str = snap_type_strings[snap_ind];
2164 if (str != snap_type_selector.get_text()) {
2165 snap_type_selector.set_text (str);
2170 switch (_snap_type) {
2171 case SnapToBeatDiv128:
2172 case SnapToBeatDiv64:
2173 case SnapToBeatDiv32:
2174 case SnapToBeatDiv28:
2175 case SnapToBeatDiv24:
2176 case SnapToBeatDiv20:
2177 case SnapToBeatDiv16:
2178 case SnapToBeatDiv14:
2179 case SnapToBeatDiv12:
2180 case SnapToBeatDiv10:
2181 case SnapToBeatDiv8:
2182 case SnapToBeatDiv7:
2183 case SnapToBeatDiv6:
2184 case SnapToBeatDiv5:
2185 case SnapToBeatDiv4:
2186 case SnapToBeatDiv3:
2187 case SnapToBeatDiv2: {
2188 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2189 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2191 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2192 current_bbt_points_begin, current_bbt_points_end);
2193 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2194 current_bbt_points_begin, current_bbt_points_end);
2195 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2199 case SnapToRegionStart:
2200 case SnapToRegionEnd:
2201 case SnapToRegionSync:
2202 case SnapToRegionBoundary:
2203 build_region_boundary_cache ();
2211 redisplay_tempo (false);
2213 SnapChanged (); /* EMIT SIGNAL */
2217 Editor::set_snap_mode (SnapMode mode)
2219 string str = snap_mode_strings[(int)mode];
2221 if (internal_editing()) {
2222 internal_snap_mode = mode;
2224 pre_internal_snap_mode = mode;
2229 if (str != snap_mode_selector.get_text ()) {
2230 snap_mode_selector.set_text (str);
2237 Editor::set_edit_point_preference (EditPoint ep, bool force)
2239 bool changed = (_edit_point != ep);
2242 if (Profile->get_mixbus())
2243 if (ep == EditAtSelectedMarker)
2244 ep = EditAtPlayhead;
2246 string str = edit_point_strings[(int)ep];
2247 if (str != edit_point_selector.get_text ()) {
2248 edit_point_selector.set_text (str);
2251 update_all_enter_cursors();
2253 if (!force && !changed) {
2257 const char* action=NULL;
2259 switch (_edit_point) {
2260 case EditAtPlayhead:
2261 action = "edit-at-playhead";
2263 case EditAtSelectedMarker:
2264 action = "edit-at-marker";
2267 action = "edit-at-mouse";
2271 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2273 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2277 bool in_track_canvas;
2279 if (!mouse_frame (foo, in_track_canvas)) {
2280 in_track_canvas = false;
2283 reset_canvas_action_sensitivity (in_track_canvas);
2289 Editor::set_state (const XMLNode& node, int version)
2291 XMLProperty const * prop;
2293 PBD::Unwinder<bool> nsi (no_save_instant, true);
2295 Tabbable::set_state (node, version);
2297 if (_session && (prop = node.property ("playhead"))) {
2299 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2301 playhead_cursor->set_position (pos);
2303 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2304 playhead_cursor->set_position (0);
2307 playhead_cursor->set_position (0);
2310 if ((prop = node.property ("mixer-width"))) {
2311 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2314 if ((prop = node.property ("zoom-focus"))) {
2315 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2318 if ((prop = node.property ("zoom"))) {
2319 /* older versions of ardour used floating point samples_per_pixel */
2320 double f = PBD::atof (prop->value());
2321 reset_zoom (llrintf (f));
2323 reset_zoom (samples_per_pixel);
2326 if ((prop = node.property ("visible-track-count"))) {
2327 set_visible_track_count (PBD::atoi (prop->value()));
2330 if ((prop = node.property ("snap-to"))) {
2331 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2332 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2335 if ((prop = node.property ("snap-mode"))) {
2336 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2337 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2338 * snap_mode_selection_done() will only mark an already active item as active
2339 * which does not trigger set_text().
2341 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2344 if ((prop = node.property ("internal-snap-to"))) {
2345 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2348 if ((prop = node.property ("internal-snap-mode"))) {
2349 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2352 if ((prop = node.property ("pre-internal-snap-to"))) {
2353 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2356 if ((prop = node.property ("pre-internal-snap-mode"))) {
2357 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2360 if ((prop = node.property ("mouse-mode"))) {
2361 MouseMode m = str2mousemode(prop->value());
2362 set_mouse_mode (m, true);
2364 set_mouse_mode (MouseObject, true);
2367 if ((prop = node.property ("left-frame")) != 0) {
2369 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2373 reset_x_origin (pos);
2377 if ((prop = node.property ("y-origin")) != 0) {
2378 reset_y_origin (atof (prop->value ()));
2381 if ((prop = node.property ("join-object-range"))) {
2382 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2383 bool yn = string_is_affirmative (prop->value());
2385 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2386 tact->set_active (!yn);
2387 tact->set_active (yn);
2389 set_mouse_mode(mouse_mode, true);
2392 if ((prop = node.property ("edit-point"))) {
2393 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2396 if ((prop = node.property ("show-measures"))) {
2397 bool yn = string_is_affirmative (prop->value());
2398 _show_measures = yn;
2401 if ((prop = node.property ("follow-playhead"))) {
2402 bool yn = string_is_affirmative (prop->value());
2403 set_follow_playhead (yn);
2406 if ((prop = node.property ("stationary-playhead"))) {
2407 bool yn = string_is_affirmative (prop->value());
2408 set_stationary_playhead (yn);
2411 if ((prop = node.property ("region-list-sort-type"))) {
2412 RegionListSortType st;
2413 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2416 if ((prop = node.property ("show-editor-mixer"))) {
2418 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2421 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2422 bool yn = string_is_affirmative (prop->value());
2424 /* do it twice to force the change */
2426 tact->set_active (!yn);
2427 tact->set_active (yn);
2430 if ((prop = node.property ("show-editor-list"))) {
2432 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2435 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2436 bool yn = string_is_affirmative (prop->value());
2438 /* do it twice to force the change */
2440 tact->set_active (!yn);
2441 tact->set_active (yn);
2444 if ((prop = node.property (X_("editor-list-page")))) {
2445 _the_notebook.set_current_page (atoi (prop->value ()));
2448 if ((prop = node.property (X_("show-marker-lines")))) {
2449 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2451 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2452 bool yn = string_is_affirmative (prop->value ());
2454 tact->set_active (!yn);
2455 tact->set_active (yn);
2458 XMLNodeList children = node.children ();
2459 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2460 selection->set_state (**i, Stateful::current_state_version);
2461 _regions->set_state (**i);
2464 if ((prop = node.property ("maximised"))) {
2465 bool yn = string_is_affirmative (prop->value());
2466 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2468 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2469 bool fs = tact && tact->get_active();
2471 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2475 if ((prop = node.property ("nudge-clock-value"))) {
2477 sscanf (prop->value().c_str(), "%" PRId64, &f);
2478 nudge_clock->set (f);
2480 nudge_clock->set_mode (AudioClock::Timecode);
2481 nudge_clock->set (_session->frame_rate() * 5, true);
2486 * Not all properties may have been in XML, but
2487 * those that are linked to a private variable may need changing
2492 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2494 yn = _show_measures;
2495 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2496 /* do it twice to force the change */
2497 tact->set_active (!yn);
2498 tact->set_active (yn);
2501 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2502 yn = _follow_playhead;
2504 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2505 if (tact->get_active() != yn) {
2506 tact->set_active (yn);
2510 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2511 yn = _stationary_playhead;
2513 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2514 if (tact->get_active() != yn) {
2515 tact->set_active (yn);
2520 return LuaInstance::instance()->set_state(node);
2524 Editor::get_state ()
2526 XMLNode* node = new XMLNode (X_("Editor"));
2529 id().print (buf, sizeof (buf));
2530 node->add_property ("id", buf);
2532 node->add_child_nocopy (Tabbable::get_state());
2534 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2535 node->add_property("edit-horizontal-pane-pos", string(buf));
2536 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2537 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2538 node->add_property("edit-vertical-pane-pos", string(buf));
2540 maybe_add_mixer_strip_width (*node);
2542 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2544 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2545 node->add_property ("zoom", buf);
2546 node->add_property ("snap-to", enum_2_string (_snap_type));
2547 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2548 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2549 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2550 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2551 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2552 node->add_property ("edit-point", enum_2_string (_edit_point));
2553 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2554 node->add_property ("visible-track-count", buf);
2556 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2557 node->add_property ("playhead", buf);
2558 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2559 node->add_property ("left-frame", buf);
2560 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2561 node->add_property ("y-origin", buf);
2563 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2564 node->add_property ("maximised", _maximised ? "yes" : "no");
2565 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2566 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2567 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2568 node->add_property ("mouse-mode", enum2str(mouse_mode));
2569 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2571 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2573 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2574 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2577 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2579 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2580 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2583 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2584 node->add_property (X_("editor-list-page"), buf);
2586 if (button_bindings) {
2587 XMLNode* bb = new XMLNode (X_("Buttons"));
2588 button_bindings->save (*bb);
2589 node->add_child_nocopy (*bb);
2592 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2594 node->add_child_nocopy (selection->get_state ());
2595 node->add_child_nocopy (_regions->get_state ());
2597 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2598 node->add_property ("nudge-clock-value", buf);
2600 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2601 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2606 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2607 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2609 * @return pair: TimeAxisView that y is over, layer index.
2611 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2612 * in stacked or expanded region display mode, otherwise 0.
2614 std::pair<TimeAxisView *, double>
2615 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2617 if (!trackview_relative_offset) {
2618 y -= _trackview_group->canvas_origin().y;
2622 return std::make_pair ( (TimeAxisView *) 0, 0);
2625 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2627 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2634 return std::make_pair ( (TimeAxisView *) 0, 0);
2637 /** Snap a position to the grid, if appropriate, taking into account current
2638 * grid settings and also the state of any snap modifier keys that may be pressed.
2639 * @param start Position to snap.
2640 * @param event Event to get current key modifier information from, or 0.
2643 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2645 if (!_session || !event) {
2649 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2650 if (_snap_mode == SnapOff) {
2651 snap_to_internal (start, direction, for_mark);
2654 if (_snap_mode != SnapOff) {
2655 snap_to_internal (start, direction, for_mark);
2656 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2657 /* SnapOff, but we pressed the snap_delta modifier */
2658 snap_to_internal (start, direction, for_mark);
2664 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2666 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2670 snap_to_internal (start, direction, for_mark, ensure_snap);
2674 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2676 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2677 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2679 switch (_snap_type) {
2680 case SnapToTimecodeFrame:
2681 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2682 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2683 /* start is already on a whole timecode frame, do nothing */
2684 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2685 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2687 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2691 case SnapToTimecodeSeconds:
2692 if (_session->config.get_timecode_offset_negative()) {
2693 start += _session->config.get_timecode_offset ();
2695 start -= _session->config.get_timecode_offset ();
2697 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2698 (start % one_timecode_second == 0)) {
2699 /* start is already on a whole second, do nothing */
2700 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2701 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2703 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2706 if (_session->config.get_timecode_offset_negative()) {
2707 start -= _session->config.get_timecode_offset ();
2709 start += _session->config.get_timecode_offset ();
2713 case SnapToTimecodeMinutes:
2714 if (_session->config.get_timecode_offset_negative()) {
2715 start += _session->config.get_timecode_offset ();
2717 start -= _session->config.get_timecode_offset ();
2719 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2720 (start % one_timecode_minute == 0)) {
2721 /* start is already on a whole minute, do nothing */
2722 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2723 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2725 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2727 if (_session->config.get_timecode_offset_negative()) {
2728 start -= _session->config.get_timecode_offset ();
2730 start += _session->config.get_timecode_offset ();
2734 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2735 abort(); /*NOTREACHED*/
2740 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2742 const framepos_t one_second = _session->frame_rate();
2743 const framepos_t one_minute = _session->frame_rate() * 60;
2744 framepos_t presnap = start;
2748 switch (_snap_type) {
2749 case SnapToTimecodeFrame:
2750 case SnapToTimecodeSeconds:
2751 case SnapToTimecodeMinutes:
2752 return timecode_snap_to_internal (start, direction, for_mark);
2755 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2756 start % (one_second/75) == 0) {
2757 /* start is already on a whole CD frame, do nothing */
2758 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2759 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2761 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2766 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2767 start % one_second == 0) {
2768 /* start is already on a whole second, do nothing */
2769 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2770 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2772 start = (framepos_t) floor ((double) start / one_second) * one_second;
2777 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2778 start % one_minute == 0) {
2779 /* start is already on a whole minute, do nothing */
2780 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2781 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2783 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2788 start = _session->tempo_map().round_to_bar (start, direction);
2792 start = _session->tempo_map().round_to_beat (start, direction);
2795 case SnapToBeatDiv128:
2796 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2798 case SnapToBeatDiv64:
2799 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2801 case SnapToBeatDiv32:
2802 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2804 case SnapToBeatDiv28:
2805 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2807 case SnapToBeatDiv24:
2808 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2810 case SnapToBeatDiv20:
2811 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2813 case SnapToBeatDiv16:
2814 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2816 case SnapToBeatDiv14:
2817 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2819 case SnapToBeatDiv12:
2820 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2822 case SnapToBeatDiv10:
2823 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2825 case SnapToBeatDiv8:
2826 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2828 case SnapToBeatDiv7:
2829 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2831 case SnapToBeatDiv6:
2832 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2834 case SnapToBeatDiv5:
2835 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2837 case SnapToBeatDiv4:
2838 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2840 case SnapToBeatDiv3:
2841 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2843 case SnapToBeatDiv2:
2844 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2852 _session->locations()->marks_either_side (start, before, after);
2854 if (before == max_framepos && after == max_framepos) {
2855 /* No marks to snap to, so just don't snap */
2857 } else if (before == max_framepos) {
2859 } else if (after == max_framepos) {
2861 } else if (before != max_framepos && after != max_framepos) {
2862 /* have before and after */
2863 if ((start - before) < (after - start)) {
2872 case SnapToRegionStart:
2873 case SnapToRegionEnd:
2874 case SnapToRegionSync:
2875 case SnapToRegionBoundary:
2876 if (!region_boundary_cache.empty()) {
2878 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2879 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2881 if (direction > 0) {
2882 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2884 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2887 if (next != region_boundary_cache.begin ()) {
2892 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2893 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2895 if (start > (p + n) / 2) {
2904 switch (_snap_mode) {
2914 if (presnap > start) {
2915 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2919 } else if (presnap < start) {
2920 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2926 /* handled at entry */
2934 Editor::setup_toolbar ()
2936 HBox* mode_box = manage(new HBox);
2937 mode_box->set_border_width (2);
2938 mode_box->set_spacing(2);
2940 HBox* mouse_mode_box = manage (new HBox);
2941 HBox* mouse_mode_hbox = manage (new HBox);
2942 VBox* mouse_mode_vbox = manage (new VBox);
2943 Alignment* mouse_mode_align = manage (new Alignment);
2945 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2946 mouse_mode_size_group->add_widget (smart_mode_button);
2947 mouse_mode_size_group->add_widget (mouse_move_button);
2948 mouse_mode_size_group->add_widget (mouse_cut_button);
2949 mouse_mode_size_group->add_widget (mouse_select_button);
2950 mouse_mode_size_group->add_widget (mouse_timefx_button);
2951 mouse_mode_size_group->add_widget (mouse_audition_button);
2952 mouse_mode_size_group->add_widget (mouse_draw_button);
2953 mouse_mode_size_group->add_widget (mouse_content_button);
2955 mouse_mode_size_group->add_widget (zoom_in_button);
2956 mouse_mode_size_group->add_widget (zoom_out_button);
2957 mouse_mode_size_group->add_widget (zoom_preset_selector);
2958 mouse_mode_size_group->add_widget (zoom_out_full_button);
2959 mouse_mode_size_group->add_widget (zoom_focus_selector);
2961 mouse_mode_size_group->add_widget (tav_shrink_button);
2962 mouse_mode_size_group->add_widget (tav_expand_button);
2963 mouse_mode_size_group->add_widget (visible_tracks_selector);
2965 mouse_mode_size_group->add_widget (snap_type_selector);
2966 mouse_mode_size_group->add_widget (snap_mode_selector);
2968 mouse_mode_size_group->add_widget (edit_point_selector);
2969 mouse_mode_size_group->add_widget (edit_mode_selector);
2971 mouse_mode_size_group->add_widget (*nudge_clock);
2972 mouse_mode_size_group->add_widget (nudge_forward_button);
2973 mouse_mode_size_group->add_widget (nudge_backward_button);
2975 mouse_mode_hbox->set_spacing (2);
2977 if (!ARDOUR::Profile->get_trx()) {
2978 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2981 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2982 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2984 if (!ARDOUR::Profile->get_mixbus()) {
2985 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2988 if (!ARDOUR::Profile->get_trx()) {
2989 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2990 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2991 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2992 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2995 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2997 mouse_mode_align->add (*mouse_mode_vbox);
2998 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3000 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3002 edit_mode_selector.set_name ("mouse mode button");
3004 if (!ARDOUR::Profile->get_trx()) {
3005 mode_box->pack_start (edit_mode_selector, false, false);
3008 mode_box->pack_start (*mouse_mode_box, false, false);
3012 _zoom_box.set_spacing (2);
3013 _zoom_box.set_border_width (2);
3017 zoom_preset_selector.set_name ("zoom button");
3018 zoom_preset_selector.set_image(::get_icon ("time_exp"));
3019 zoom_preset_selector.set_size_request (42, -1);
3021 zoom_in_button.set_name ("zoom button");
3022 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3023 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3024 zoom_in_button.set_related_action (act);
3026 zoom_out_button.set_name ("zoom button");
3027 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3028 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3029 zoom_out_button.set_related_action (act);
3031 zoom_out_full_button.set_name ("zoom button");
3032 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3033 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3034 zoom_out_full_button.set_related_action (act);
3036 zoom_focus_selector.set_name ("zoom button");
3038 if (ARDOUR::Profile->get_mixbus()) {
3039 _zoom_box.pack_start (zoom_preset_selector, false, false);
3040 } else if (ARDOUR::Profile->get_trx()) {
3041 mode_box->pack_start (zoom_out_button, false, false);
3042 mode_box->pack_start (zoom_in_button, false, false);
3044 _zoom_box.pack_start (zoom_out_button, false, false);
3045 _zoom_box.pack_start (zoom_in_button, false, false);
3046 _zoom_box.pack_start (zoom_out_full_button, false, false);
3047 _zoom_box.pack_start (zoom_focus_selector, false, false);
3050 /* Track zoom buttons */
3051 visible_tracks_selector.set_name ("zoom button");
3052 if (Profile->get_mixbus()) {
3053 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3054 visible_tracks_selector.set_size_request (42, -1);
3056 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3059 tav_expand_button.set_name ("zoom button");
3060 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3061 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3062 tav_expand_button.set_related_action (act);
3064 tav_shrink_button.set_name ("zoom button");
3065 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3066 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3067 tav_shrink_button.set_related_action (act);
3069 if (ARDOUR::Profile->get_mixbus()) {
3070 _zoom_box.pack_start (visible_tracks_selector);
3071 } else if (ARDOUR::Profile->get_trx()) {
3072 _zoom_box.pack_start (tav_shrink_button);
3073 _zoom_box.pack_start (tav_expand_button);
3075 _zoom_box.pack_start (visible_tracks_selector);
3076 _zoom_box.pack_start (tav_shrink_button);
3077 _zoom_box.pack_start (tav_expand_button);
3080 snap_box.set_spacing (2);
3081 snap_box.set_border_width (2);
3083 snap_type_selector.set_name ("mouse mode button");
3085 snap_mode_selector.set_name ("mouse mode button");
3087 edit_point_selector.set_name ("mouse mode button");
3089 snap_box.pack_start (snap_mode_selector, false, false);
3090 snap_box.pack_start (snap_type_selector, false, false);
3091 snap_box.pack_start (edit_point_selector, false, false);
3095 HBox *nudge_box = manage (new HBox);
3096 nudge_box->set_spacing (2);
3097 nudge_box->set_border_width (2);
3099 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3100 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3102 nudge_box->pack_start (nudge_backward_button, false, false);
3103 nudge_box->pack_start (nudge_forward_button, false, false);
3104 nudge_box->pack_start (*nudge_clock, false, false);
3107 /* Pack everything in... */
3109 HBox* hbox = manage (new HBox);
3110 hbox->set_spacing(2);
3112 toolbar_hbox.set_spacing (2);
3113 toolbar_hbox.set_border_width (1);
3115 toolbar_hbox.pack_start (*mode_box, false, false);
3116 if (!ARDOUR::Profile->get_trx()) {
3117 toolbar_hbox.pack_start (_zoom_box, false, false);
3118 toolbar_hbox.pack_start (*hbox, false, false);
3121 if (!ARDOUR::Profile->get_trx()) {
3122 hbox->pack_start (snap_box, false, false);
3123 hbox->pack_start (*nudge_box, false, false);
3128 toolbar_base.set_name ("ToolBarBase");
3129 toolbar_base.add (toolbar_hbox);
3131 _toolbar_viewport.add (toolbar_base);
3132 /* stick to the required height but allow width to vary if there's not enough room */
3133 _toolbar_viewport.set_size_request (1, -1);
3135 toolbar_frame.set_shadow_type (SHADOW_OUT);
3136 toolbar_frame.set_name ("BaseFrame");
3137 toolbar_frame.add (_toolbar_viewport);
3141 Editor::build_edit_point_menu ()
3143 using namespace Menu_Helpers;
3145 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3146 if(!Profile->get_mixbus())
3147 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3148 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3150 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3154 Editor::build_edit_mode_menu ()
3156 using namespace Menu_Helpers;
3158 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3159 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3160 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3161 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3163 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3167 Editor::build_snap_mode_menu ()
3169 using namespace Menu_Helpers;
3171 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3172 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3173 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3175 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3179 Editor::build_snap_type_menu ()
3181 using namespace Menu_Helpers;
3183 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3184 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3185 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3186 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3187 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3188 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3189 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3190 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3191 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3192 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3193 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3194 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3195 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3196 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3197 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3198 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3199 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3200 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3201 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3202 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3203 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3204 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3205 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3206 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3207 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3208 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3209 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3210 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3211 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3212 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3214 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3219 Editor::setup_tooltips ()
3221 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3222 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3223 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3224 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3225 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3226 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3227 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3228 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3229 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3230 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3231 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3232 set_tooltip (zoom_in_button, _("Zoom In"));
3233 set_tooltip (zoom_out_button, _("Zoom Out"));
3234 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3235 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3236 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3237 set_tooltip (tav_expand_button, _("Expand Tracks"));
3238 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3239 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3240 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3241 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3242 set_tooltip (edit_point_selector, _("Edit Point"));
3243 set_tooltip (edit_mode_selector, _("Edit Mode"));
3244 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3248 Editor::convert_drop_to_paths (
3249 vector<string>& paths,
3250 const RefPtr<Gdk::DragContext>& /*context*/,
3253 const SelectionData& data,
3257 if (_session == 0) {
3261 vector<string> uris = data.get_uris();
3265 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3266 are actually URI lists. So do it by hand.
3269 if (data.get_target() != "text/plain") {
3273 /* Parse the "uri-list" format that Nautilus provides,
3274 where each pathname is delimited by \r\n.
3276 THERE MAY BE NO NULL TERMINATING CHAR!!!
3279 string txt = data.get_text();
3283 p = (char *) malloc (txt.length() + 1);
3284 txt.copy (p, txt.length(), 0);
3285 p[txt.length()] = '\0';
3291 while (g_ascii_isspace (*p))
3295 while (*q && (*q != '\n') && (*q != '\r')) {
3302 while (q > p && g_ascii_isspace (*q))
3307 uris.push_back (string (p, q - p + 1));
3311 p = strchr (p, '\n');
3323 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3324 if ((*i).substr (0,7) == "file://") {
3325 paths.push_back (Glib::filename_from_uri (*i));
3333 Editor::new_tempo_section ()
3338 Editor::map_transport_state ()
3340 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3342 if (_session && _session->transport_stopped()) {
3343 have_pending_keyboard_selection = false;
3346 update_loop_range_view ();
3352 Editor::begin_selection_op_history ()
3354 selection_op_cmd_depth = 0;
3355 selection_op_history_it = 0;
3357 while(!selection_op_history.empty()) {
3358 delete selection_op_history.front();
3359 selection_op_history.pop_front();
3362 selection_undo_action->set_sensitive (false);
3363 selection_redo_action->set_sensitive (false);
3364 selection_op_history.push_front (&_selection_memento->get_state ());
3368 Editor::begin_reversible_selection_op (string name)
3371 //cerr << name << endl;
3372 /* begin/commit pairs can be nested */
3373 selection_op_cmd_depth++;
3378 Editor::commit_reversible_selection_op ()
3381 if (selection_op_cmd_depth == 1) {
3383 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3385 The user has undone some selection ops and then made a new one,
3386 making anything earlier in the list invalid.
3389 list<XMLNode *>::iterator it = selection_op_history.begin();
3390 list<XMLNode *>::iterator e_it = it;
3391 advance (e_it, selection_op_history_it);
3393 for ( ; it != e_it; ++it) {
3396 selection_op_history.erase (selection_op_history.begin(), e_it);
3399 selection_op_history.push_front (&_selection_memento->get_state ());
3400 selection_op_history_it = 0;
3402 selection_undo_action->set_sensitive (true);
3403 selection_redo_action->set_sensitive (false);
3406 if (selection_op_cmd_depth > 0) {
3407 selection_op_cmd_depth--;
3413 Editor::undo_selection_op ()
3416 selection_op_history_it++;
3418 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3419 if (n == selection_op_history_it) {
3420 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3421 selection_redo_action->set_sensitive (true);
3425 /* is there an earlier entry? */
3426 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3427 selection_undo_action->set_sensitive (false);
3433 Editor::redo_selection_op ()
3436 if (selection_op_history_it > 0) {
3437 selection_op_history_it--;
3440 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3441 if (n == selection_op_history_it) {
3442 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3443 selection_undo_action->set_sensitive (true);
3448 if (selection_op_history_it == 0) {
3449 selection_redo_action->set_sensitive (false);
3455 Editor::begin_reversible_command (string name)
3458 before.push_back (&_selection_memento->get_state ());
3459 _session->begin_reversible_command (name);
3464 Editor::begin_reversible_command (GQuark q)
3467 before.push_back (&_selection_memento->get_state ());
3468 _session->begin_reversible_command (q);
3473 Editor::abort_reversible_command ()
3476 while(!before.empty()) {
3477 delete before.front();
3480 _session->abort_reversible_command ();
3485 Editor::commit_reversible_command ()
3488 if (before.size() == 1) {
3489 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3490 redo_action->set_sensitive(false);
3491 undo_action->set_sensitive(true);
3492 begin_selection_op_history ();
3495 if (before.empty()) {
3496 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3501 _session->commit_reversible_command ();
3506 Editor::history_changed ()
3510 if (undo_action && _session) {
3511 if (_session->undo_depth() == 0) {
3512 label = S_("Command|Undo");
3514 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3516 undo_action->property_label() = label;
3519 if (redo_action && _session) {
3520 if (_session->redo_depth() == 0) {
3522 redo_action->set_sensitive (false);
3524 label = string_compose(_("Redo (%1)"), _session->next_redo());
3525 redo_action->set_sensitive (true);
3527 redo_action->property_label() = label;
3532 Editor::duplicate_range (bool with_dialog)
3536 RegionSelection rs = get_regions_from_selection_and_entered ();
3538 if ( selection->time.length() == 0 && rs.empty()) {
3544 ArdourDialog win (_("Duplicate"));
3545 Label label (_("Number of duplications:"));
3546 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3547 SpinButton spinner (adjustment, 0.0, 1);
3550 win.get_vbox()->set_spacing (12);
3551 win.get_vbox()->pack_start (hbox);
3552 hbox.set_border_width (6);
3553 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3555 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3556 place, visually. so do this by hand.
3559 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3560 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3561 spinner.grab_focus();
3567 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3568 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3569 win.set_default_response (RESPONSE_ACCEPT);
3571 spinner.grab_focus ();
3573 switch (win.run ()) {
3574 case RESPONSE_ACCEPT:
3580 times = adjustment.get_value();
3583 if ((current_mouse_mode() == Editing::MouseRange)) {
3584 if (selection->time.length()) {
3585 duplicate_selection (times);
3587 } else if (get_smart_mode()) {
3588 if (selection->time.length()) {
3589 duplicate_selection (times);
3591 duplicate_some_regions (rs, times);
3593 duplicate_some_regions (rs, times);
3598 Editor::set_edit_mode (EditMode m)
3600 Config->set_edit_mode (m);
3604 Editor::cycle_edit_mode ()
3606 switch (Config->get_edit_mode()) {
3608 Config->set_edit_mode (Ripple);
3612 Config->set_edit_mode (Lock);
3615 Config->set_edit_mode (Slide);
3621 Editor::edit_mode_selection_done ( EditMode m )
3623 Config->set_edit_mode ( m );
3627 Editor::snap_type_selection_done (SnapType snaptype)
3629 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3631 ract->set_active ();
3636 Editor::snap_mode_selection_done (SnapMode mode)
3638 RefPtr<RadioAction> ract = snap_mode_action (mode);
3641 ract->set_active (true);
3646 Editor::cycle_edit_point (bool with_marker)
3648 if(Profile->get_mixbus())
3649 with_marker = false;
3651 switch (_edit_point) {
3653 set_edit_point_preference (EditAtPlayhead);
3655 case EditAtPlayhead:
3657 set_edit_point_preference (EditAtSelectedMarker);
3659 set_edit_point_preference (EditAtMouse);
3662 case EditAtSelectedMarker:
3663 set_edit_point_preference (EditAtMouse);
3669 Editor::edit_point_selection_done (EditPoint ep)
3671 set_edit_point_preference ( ep );
3675 Editor::build_zoom_focus_menu ()
3677 using namespace Menu_Helpers;
3679 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3680 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3681 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3682 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3683 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3684 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3686 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3690 Editor::zoom_focus_selection_done ( ZoomFocus f )
3692 RefPtr<RadioAction> ract = zoom_focus_action (f);
3694 ract->set_active ();
3699 Editor::build_track_count_menu ()
3701 using namespace Menu_Helpers;
3703 if (!Profile->get_mixbus()) {
3704 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3705 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3706 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3707 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3708 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3709 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3710 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3711 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3712 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3713 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3714 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3715 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3716 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3718 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3719 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3720 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3721 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3722 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3723 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3724 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3725 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3726 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3727 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3729 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3730 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3731 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3732 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3733 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3734 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3735 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3736 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3737 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3738 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3739 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3744 Editor::set_zoom_preset (int64_t ms)
3747 temporal_zoom_session();
3751 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3752 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3756 Editor::set_visible_track_count (int32_t n)
3758 _visible_track_count = n;
3760 /* if the canvas hasn't really been allocated any size yet, just
3761 record the desired number of visible tracks and return. when canvas
3762 allocation happens, we will get called again and then we can do the
3766 if (_visible_canvas_height <= 1) {
3772 DisplaySuspender ds;
3774 if (_visible_track_count > 0) {
3775 h = trackviews_height() / _visible_track_count;
3776 std::ostringstream s;
3777 s << _visible_track_count;
3779 } else if (_visible_track_count == 0) {
3781 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3782 if ((*i)->marked_for_display()) {
3786 h = trackviews_height() / n;
3789 /* negative value means that the visible track count has
3790 been overridden by explicit track height changes.
3792 visible_tracks_selector.set_text (X_("*"));
3796 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3797 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3800 if (str != visible_tracks_selector.get_text()) {
3801 visible_tracks_selector.set_text (str);
3806 Editor::override_visible_track_count ()
3808 _visible_track_count = -1;
3809 visible_tracks_selector.set_text ( _("*") );
3813 Editor::edit_controls_button_release (GdkEventButton* ev)
3815 if (Keyboard::is_context_menu_event (ev)) {
3816 ARDOUR_UI::instance()->add_route ();
3817 } else if (ev->button == 1) {
3818 selection->clear_tracks ();
3825 Editor::mouse_select_button_release (GdkEventButton* ev)
3827 /* this handles just right-clicks */
3829 if (ev->button != 3) {
3837 Editor::set_zoom_focus (ZoomFocus f)
3839 string str = zoom_focus_strings[(int)f];
3841 if (str != zoom_focus_selector.get_text()) {
3842 zoom_focus_selector.set_text (str);
3845 if (zoom_focus != f) {
3852 Editor::cycle_zoom_focus ()
3854 switch (zoom_focus) {
3856 set_zoom_focus (ZoomFocusRight);
3858 case ZoomFocusRight:
3859 set_zoom_focus (ZoomFocusCenter);
3861 case ZoomFocusCenter:
3862 set_zoom_focus (ZoomFocusPlayhead);
3864 case ZoomFocusPlayhead:
3865 set_zoom_focus (ZoomFocusMouse);
3867 case ZoomFocusMouse:
3868 set_zoom_focus (ZoomFocusEdit);
3871 set_zoom_focus (ZoomFocusLeft);
3877 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3879 /* recover or initialize pane positions. do this here rather than earlier because
3880 we don't want the positions to change the child allocations, which they seem to do.
3884 XMLProperty const * prop;
3886 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3895 XMLNode* geometry = find_named_node (*node, "geometry");
3897 if (which == static_cast<Paned*> (&edit_pane)) {
3899 if (done & Horizontal) {
3903 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3904 _notebook_shrunk = string_is_affirmative (prop->value ());
3907 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3908 /* initial allocation is 90% to canvas, 10% to notebook */
3909 pos = (int) floor (alloc.get_width() * 0.90f);
3910 snprintf (buf, sizeof(buf), "%d", pos);
3912 pos = atoi (prop->value());
3915 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3916 edit_pane.set_position (pos);
3919 done = (Pane) (done | Horizontal);
3921 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3923 if (done & Vertical) {
3927 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3928 /* initial allocation is 90% to canvas, 10% to summary */
3929 pos = (int) floor (alloc.get_height() * 0.90f);
3930 snprintf (buf, sizeof(buf), "%d", pos);
3933 pos = atoi (prop->value());
3936 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3937 editor_summary_pane.set_position (pos);
3940 done = (Pane) (done | Vertical);
3945 Editor::set_show_measures (bool yn)
3947 if (_show_measures != yn) {
3950 if ((_show_measures = yn) == true) {
3952 tempo_lines->show();
3955 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3956 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3958 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3959 draw_measures (begin, end);
3967 Editor::toggle_follow_playhead ()
3969 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3971 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3972 set_follow_playhead (tact->get_active());
3976 /** @param yn true to follow playhead, otherwise false.
3977 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3980 Editor::set_follow_playhead (bool yn, bool catch_up)
3982 if (_follow_playhead != yn) {
3983 if ((_follow_playhead = yn) == true && catch_up) {
3985 reset_x_origin_to_follow_playhead ();
3992 Editor::toggle_stationary_playhead ()
3994 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3996 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3997 set_stationary_playhead (tact->get_active());
4002 Editor::set_stationary_playhead (bool yn)
4004 if (_stationary_playhead != yn) {
4005 if ((_stationary_playhead = yn) == true) {
4007 // FIXME need a 3.0 equivalent of this 2.X call
4008 // update_current_screen ();
4015 Editor::playlist_selector () const
4017 return *_playlist_selector;
4021 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4023 if (paste_count == 0) {
4024 /* don't bother calculating an offset that will be zero anyway */
4028 /* calculate basic unsnapped multi-paste offset */
4029 framecnt_t offset = paste_count * duration;
4031 /* snap offset so pos + offset is aligned to the grid */
4032 framepos_t offset_pos = pos + offset;
4033 snap_to(offset_pos, RoundUpMaybe);
4034 offset = offset_pos - pos;
4040 Editor::get_grid_beat_divisions(framepos_t position)
4042 switch (_snap_type) {
4043 case SnapToBeatDiv128: return 128;
4044 case SnapToBeatDiv64: return 64;
4045 case SnapToBeatDiv32: return 32;
4046 case SnapToBeatDiv28: return 28;
4047 case SnapToBeatDiv24: return 24;
4048 case SnapToBeatDiv20: return 20;
4049 case SnapToBeatDiv16: return 16;
4050 case SnapToBeatDiv14: return 14;
4051 case SnapToBeatDiv12: return 12;
4052 case SnapToBeatDiv10: return 10;
4053 case SnapToBeatDiv8: return 8;
4054 case SnapToBeatDiv7: return 7;
4055 case SnapToBeatDiv6: return 6;
4056 case SnapToBeatDiv5: return 5;
4057 case SnapToBeatDiv4: return 4;
4058 case SnapToBeatDiv3: return 3;
4059 case SnapToBeatDiv2: return 2;
4066 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4070 const unsigned divisions = get_grid_beat_divisions(position);
4072 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4075 switch (_snap_type) {
4077 return Evoral::Beats(1.0);
4080 return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
4088 return Evoral::Beats();
4092 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4096 ret = nudge_clock->current_duration (pos);
4097 next = ret + 1; /* XXXX fix me */
4103 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4105 ArdourDialog dialog (_("Playlist Deletion"));
4106 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4107 "If it is kept, its audio files will not be cleaned.\n"
4108 "If it is deleted, audio files used by it alone will be cleaned."),
4111 dialog.set_position (WIN_POS_CENTER);
4112 dialog.get_vbox()->pack_start (label);
4116 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4117 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4118 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4119 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4120 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4122 // by default gtk uses the left most button
4123 keep->grab_focus ();
4125 switch (dialog.run ()) {
4127 /* keep this and all remaining ones */
4132 /* delete this and all others */
4136 case RESPONSE_ACCEPT:
4137 /* delete the playlist */
4141 case RESPONSE_REJECT:
4142 /* keep the playlist */
4154 Editor::audio_region_selection_covers (framepos_t where)
4156 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4157 if ((*a)->region()->covers (where)) {
4166 Editor::prepare_for_cleanup ()
4168 cut_buffer->clear_regions ();
4169 cut_buffer->clear_playlists ();
4171 selection->clear_regions ();
4172 selection->clear_playlists ();
4174 _regions->suspend_redisplay ();
4178 Editor::finish_cleanup ()
4180 _regions->resume_redisplay ();
4184 Editor::transport_loop_location()
4187 return _session->locations()->auto_loop_location();
4194 Editor::transport_punch_location()
4197 return _session->locations()->auto_punch_location();
4204 Editor::control_layout_scroll (GdkEventScroll* ev)
4206 /* Just forward to the normal canvas scroll method. The coordinate
4207 systems are different but since the canvas is always larger than the
4208 track headers, and aligned with the trackview area, this will work.
4210 In the not too distant future this layout is going away anyway and
4211 headers will be on the canvas.
4213 return canvas_scroll_event (ev, false);
4217 Editor::session_state_saved (string)
4220 _snapshots->redisplay ();
4224 Editor::maximise_editing_space ()
4230 Gtk::Window* toplevel = current_toplevel();
4233 toplevel->fullscreen ();
4239 Editor::restore_editing_space ()
4245 Gtk::Window* toplevel = current_toplevel();
4248 toplevel->unfullscreen();
4254 * Make new playlists for a given track and also any others that belong
4255 * to the same active route group with the `select' property.
4260 Editor::new_playlists (TimeAxisView* v)
4262 begin_reversible_command (_("new playlists"));
4263 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4264 _session->playlists->get (playlists);
4265 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4266 commit_reversible_command ();
4270 * Use a copy of the current playlist for a given track and also any others that belong
4271 * to the same active route group with the `select' property.
4276 Editor::copy_playlists (TimeAxisView* v)
4278 begin_reversible_command (_("copy playlists"));
4279 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4280 _session->playlists->get (playlists);
4281 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4282 commit_reversible_command ();
4285 /** Clear the current playlist for a given track and also any others that belong
4286 * to the same active route group with the `select' property.
4291 Editor::clear_playlists (TimeAxisView* v)
4293 begin_reversible_command (_("clear playlists"));
4294 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4295 _session->playlists->get (playlists);
4296 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4297 commit_reversible_command ();
4301 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4303 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4307 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4309 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4313 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4315 atv.clear_playlist ();
4319 Editor::get_y_origin () const
4321 return vertical_adjustment.get_value ();
4324 /** Queue up a change to the viewport x origin.
4325 * @param frame New x origin.
4328 Editor::reset_x_origin (framepos_t frame)
4330 pending_visual_change.add (VisualChange::TimeOrigin);
4331 pending_visual_change.time_origin = frame;
4332 ensure_visual_change_idle_handler ();
4336 Editor::reset_y_origin (double y)
4338 pending_visual_change.add (VisualChange::YOrigin);
4339 pending_visual_change.y_origin = y;
4340 ensure_visual_change_idle_handler ();
4344 Editor::reset_zoom (framecnt_t spp)
4346 if (spp == samples_per_pixel) {
4350 pending_visual_change.add (VisualChange::ZoomLevel);
4351 pending_visual_change.samples_per_pixel = spp;
4352 ensure_visual_change_idle_handler ();
4356 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4358 reset_x_origin (frame);
4361 if (!no_save_visual) {
4362 undo_visual_stack.push_back (current_visual_state(false));
4366 Editor::VisualState::VisualState (bool with_tracks)
4367 : gui_state (with_tracks ? new GUIObjectState : 0)
4371 Editor::VisualState::~VisualState ()
4376 Editor::VisualState*
4377 Editor::current_visual_state (bool with_tracks)
4379 VisualState* vs = new VisualState (with_tracks);
4380 vs->y_position = vertical_adjustment.get_value();
4381 vs->samples_per_pixel = samples_per_pixel;
4382 vs->leftmost_frame = leftmost_frame;
4383 vs->zoom_focus = zoom_focus;
4386 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4393 Editor::undo_visual_state ()
4395 if (undo_visual_stack.empty()) {
4399 VisualState* vs = undo_visual_stack.back();
4400 undo_visual_stack.pop_back();
4403 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4406 use_visual_state (*vs);
4411 Editor::redo_visual_state ()
4413 if (redo_visual_stack.empty()) {
4417 VisualState* vs = redo_visual_stack.back();
4418 redo_visual_stack.pop_back();
4420 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4421 // why do we check here?
4422 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4425 use_visual_state (*vs);
4430 Editor::swap_visual_state ()
4432 if (undo_visual_stack.empty()) {
4433 redo_visual_state ();
4435 undo_visual_state ();
4440 Editor::use_visual_state (VisualState& vs)
4442 PBD::Unwinder<bool> nsv (no_save_visual, true);
4443 DisplaySuspender ds;
4445 vertical_adjustment.set_value (vs.y_position);
4447 set_zoom_focus (vs.zoom_focus);
4448 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4451 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4453 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4454 (*i)->clear_property_cache();
4455 (*i)->reset_visual_state ();
4459 _routes->update_visibility ();
4462 /** This is the core function that controls the zoom level of the canvas. It is called
4463 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4464 * @param spp new number of samples per pixel
4467 Editor::set_samples_per_pixel (framecnt_t spp)
4473 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4474 const framecnt_t lots_of_pixels = 4000;
4476 /* if the zoom level is greater than what you'd get trying to display 3
4477 * days of audio on a really big screen, then it's too big.
4480 if (spp * lots_of_pixels > three_days) {
4484 samples_per_pixel = spp;
4487 tempo_lines->tempo_map_changed();
4490 bool const showing_time_selection = selection->time.length() > 0;
4492 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4493 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4494 (*i)->reshow_selection (selection->time);
4498 ZoomChanged (); /* EMIT_SIGNAL */
4500 ArdourCanvas::GtkCanvasViewport* c;
4502 c = get_track_canvas();
4504 c->canvas()->zoomed ();
4507 if (playhead_cursor) {
4508 playhead_cursor->set_position (playhead_cursor->current_frame ());
4511 refresh_location_display();
4512 _summary->set_overlays_dirty ();
4514 update_marker_labels ();
4520 Editor::queue_visual_videotimeline_update ()
4523 * pending_visual_change.add (VisualChange::VideoTimeline);
4524 * or maybe even more specific: which videotimeline-image
4525 * currently it calls update_video_timeline() to update
4526 * _all outdated_ images on the video-timeline.
4527 * see 'exposeimg()' in video_image_frame.cc
4529 ensure_visual_change_idle_handler ();
4533 Editor::ensure_visual_change_idle_handler ()
4535 if (pending_visual_change.idle_handler_id < 0) {
4536 // see comment in add_to_idle_resize above.
4537 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4538 pending_visual_change.being_handled = false;
4543 Editor::_idle_visual_changer (void* arg)
4545 return static_cast<Editor*>(arg)->idle_visual_changer ();
4549 Editor::idle_visual_changer ()
4551 /* set_horizontal_position() below (and maybe other calls) call
4552 gtk_main_iteration(), so it's possible that a signal will be handled
4553 half-way through this method. If this signal wants an
4554 idle_visual_changer we must schedule another one after this one, so
4555 mark the idle_handler_id as -1 here to allow that. Also make a note
4556 that we are doing the visual change, so that changes in response to
4557 super-rapid-screen-update can be dropped if we are still processing
4561 pending_visual_change.idle_handler_id = -1;
4562 pending_visual_change.being_handled = true;
4564 VisualChange vc = pending_visual_change;
4566 pending_visual_change.pending = (VisualChange::Type) 0;
4568 visual_changer (vc);
4570 pending_visual_change.being_handled = false;
4572 return 0; /* this is always a one-shot call */
4576 Editor::visual_changer (const VisualChange& vc)
4578 double const last_time_origin = horizontal_position ();
4580 if (vc.pending & VisualChange::ZoomLevel) {
4581 set_samples_per_pixel (vc.samples_per_pixel);
4583 compute_fixed_ruler_scale ();
4585 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4586 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4588 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4589 current_bbt_points_begin, current_bbt_points_end);
4590 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4591 current_bbt_points_begin, current_bbt_points_end);
4592 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4594 update_video_timeline();
4597 if (vc.pending & VisualChange::TimeOrigin) {
4598 set_horizontal_position (vc.time_origin / samples_per_pixel);
4601 if (vc.pending & VisualChange::YOrigin) {
4602 vertical_adjustment.set_value (vc.y_origin);
4605 if (last_time_origin == horizontal_position ()) {
4606 /* changed signal not emitted */
4607 update_fixed_rulers ();
4608 redisplay_tempo (true);
4611 if (!(vc.pending & VisualChange::ZoomLevel)) {
4612 update_video_timeline();
4615 _summary->set_overlays_dirty ();
4618 struct EditorOrderTimeAxisSorter {
4619 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4620 return a->order () < b->order ();
4625 Editor::sort_track_selection (TrackViewList& sel)
4627 EditorOrderTimeAxisSorter cmp;
4632 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4635 framepos_t where = 0;
4636 EditPoint ep = _edit_point;
4638 if (Profile->get_mixbus())
4639 if (ep == EditAtSelectedMarker)
4640 ep = EditAtPlayhead;
4642 if (from_outside_canvas && (ep == EditAtMouse)) {
4643 ep = EditAtPlayhead;
4644 } else if (from_context_menu && (ep == EditAtMouse)) {
4645 return canvas_event_sample (&context_click_event, 0, 0);
4648 if (entered_marker) {
4649 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4650 return entered_marker->position();
4653 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4654 ep = EditAtSelectedMarker;
4657 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4658 ep = EditAtPlayhead;
4662 case EditAtPlayhead:
4663 if (_dragging_playhead) {
4664 where = *_control_scroll_target;
4666 where = _session->audible_frame();
4668 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4671 case EditAtSelectedMarker:
4672 if (!selection->markers.empty()) {
4674 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4677 where = loc->start();
4681 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4689 if (!mouse_frame (where, ignored)) {
4690 /* XXX not right but what can we do ? */
4694 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4702 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4704 if (!_session) return;
4706 begin_reversible_command (cmd);
4710 if ((tll = transport_loop_location()) == 0) {
4711 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4712 XMLNode &before = _session->locations()->get_state();
4713 _session->locations()->add (loc, true);
4714 _session->set_auto_loop_location (loc);
4715 XMLNode &after = _session->locations()->get_state();
4716 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4718 XMLNode &before = tll->get_state();
4719 tll->set_hidden (false, this);
4720 tll->set (start, end);
4721 XMLNode &after = tll->get_state();
4722 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4725 commit_reversible_command ();
4729 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4731 if (!_session) return;
4733 begin_reversible_command (cmd);
4737 if ((tpl = transport_punch_location()) == 0) {
4738 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4739 XMLNode &before = _session->locations()->get_state();
4740 _session->locations()->add (loc, true);
4741 _session->set_auto_punch_location (loc);
4742 XMLNode &after = _session->locations()->get_state();
4743 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4745 XMLNode &before = tpl->get_state();
4746 tpl->set_hidden (false, this);
4747 tpl->set (start, end);
4748 XMLNode &after = tpl->get_state();
4749 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4752 commit_reversible_command ();
4755 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4756 * @param rs List to which found regions are added.
4757 * @param where Time to look at.
4758 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4761 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4763 const TrackViewList* tracks;
4766 tracks = &track_views;
4771 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4773 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4776 boost::shared_ptr<Track> tr;
4777 boost::shared_ptr<Playlist> pl;
4779 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4781 boost::shared_ptr<RegionList> regions = pl->regions_at (
4782 (framepos_t) floor ( (double) where * tr->speed()));
4784 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4785 RegionView* rv = rtv->view()->find_view (*i);
4796 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4798 const TrackViewList* tracks;
4801 tracks = &track_views;
4806 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4807 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4809 boost::shared_ptr<Track> tr;
4810 boost::shared_ptr<Playlist> pl;
4812 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4814 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4815 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4817 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4819 RegionView* rv = rtv->view()->find_view (*i);
4830 /** Get regions using the following method:
4832 * Make a region list using:
4833 * (a) any selected regions
4834 * (b) the intersection of any selected tracks and the edit point(*)
4835 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4837 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4839 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4843 Editor::get_regions_from_selection_and_edit_point ()
4845 RegionSelection regions;
4847 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4848 regions.add (entered_regionview);
4850 regions = selection->regions;
4853 if ( regions.empty() ) {
4854 TrackViewList tracks = selection->tracks;
4856 if (!tracks.empty()) {
4857 /* no region selected or entered, but some selected tracks:
4858 * act on all regions on the selected tracks at the edit point
4860 framepos_t const where = get_preferred_edit_position ();
4861 get_regions_at(regions, where, tracks);
4868 /** Get regions using the following method:
4870 * Make a region list using:
4871 * (a) any selected regions
4872 * (b) the intersection of any selected tracks and the edit point(*)
4873 * (c) if neither exists, then whatever region is under the mouse
4875 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4877 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4880 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4882 RegionSelection regions;
4884 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4885 regions.add (entered_regionview);
4887 regions = selection->regions;
4890 if ( regions.empty() ) {
4891 TrackViewList tracks = selection->tracks;
4893 if (!tracks.empty()) {
4894 /* no region selected or entered, but some selected tracks:
4895 * act on all regions on the selected tracks at the edit point
4897 get_regions_at(regions, pos, tracks);
4904 /** Start with regions that are selected, or the entered regionview if none are selected.
4905 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4906 * of the regions that we started with.
4910 Editor::get_regions_from_selection_and_entered () const
4912 RegionSelection regions = selection->regions;
4914 if (regions.empty() && entered_regionview) {
4915 regions.add (entered_regionview);
4922 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4924 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4925 RouteTimeAxisView* rtav;
4927 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4928 boost::shared_ptr<Playlist> pl;
4929 std::vector<boost::shared_ptr<Region> > results;
4930 boost::shared_ptr<Track> tr;
4932 if ((tr = rtav->track()) == 0) {
4937 if ((pl = (tr->playlist())) != 0) {
4938 boost::shared_ptr<Region> r = pl->region_by_id (id);
4940 RegionView* rv = rtav->view()->find_view (r);
4942 regions.push_back (rv);
4951 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4954 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4955 MidiTimeAxisView* mtav;
4957 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4959 mtav->get_per_region_note_selection (selection);
4966 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4968 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4970 RouteTimeAxisView* tatv;
4972 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4974 boost::shared_ptr<Playlist> pl;
4975 vector<boost::shared_ptr<Region> > results;
4977 boost::shared_ptr<Track> tr;
4979 if ((tr = tatv->track()) == 0) {
4984 if ((pl = (tr->playlist())) != 0) {
4985 if (src_comparison) {
4986 pl->get_source_equivalent_regions (region, results);
4988 pl->get_region_list_equivalent_regions (region, results);
4992 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4993 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4994 regions.push_back (marv);
5003 Editor::show_rhythm_ferret ()
5005 if (rhythm_ferret == 0) {
5006 rhythm_ferret = new RhythmFerret(*this);
5009 rhythm_ferret->set_session (_session);
5010 rhythm_ferret->show ();
5011 rhythm_ferret->present ();
5015 Editor::first_idle ()
5017 MessageDialog* dialog = 0;
5019 if (track_views.size() > 1) {
5020 Timers::TimerSuspender t;
5021 dialog = new MessageDialog (
5022 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5026 ARDOUR_UI::instance()->flush_pending ();
5029 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5033 // first idle adds route children (automation tracks), so we need to redisplay here
5034 _routes->redisplay ();
5038 if (_session->undo_depth() == 0) {
5039 undo_action->set_sensitive(false);
5041 redo_action->set_sensitive(false);
5042 begin_selection_op_history ();
5048 Editor::_idle_resize (gpointer arg)
5050 return ((Editor*)arg)->idle_resize ();
5054 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5056 if (resize_idle_id < 0) {
5057 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5058 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5059 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5061 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5062 _pending_resize_amount = 0;
5065 /* make a note of the smallest resulting height, so that we can clamp the
5066 lower limit at TimeAxisView::hSmall */
5068 int32_t min_resulting = INT32_MAX;
5070 _pending_resize_amount += h;
5071 _pending_resize_view = view;
5073 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5075 if (selection->tracks.contains (_pending_resize_view)) {
5076 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5077 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5081 if (min_resulting < 0) {
5086 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5087 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5091 /** Handle pending resizing of tracks */
5093 Editor::idle_resize ()
5095 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5097 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5098 selection->tracks.contains (_pending_resize_view)) {
5100 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5101 if (*i != _pending_resize_view) {
5102 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5107 _pending_resize_amount = 0;
5108 _group_tabs->set_dirty ();
5109 resize_idle_id = -1;
5117 ENSURE_GUI_THREAD (*this, &Editor::located);
5120 playhead_cursor->set_position (_session->audible_frame ());
5121 if (_follow_playhead && !_pending_initial_locate) {
5122 reset_x_origin_to_follow_playhead ();
5126 _pending_locate_request = false;
5127 _pending_initial_locate = false;
5131 Editor::region_view_added (RegionView * rv)
5133 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5134 if (rv->region ()->id () == (*pr)) {
5135 selection->add (rv);
5136 selection->regions.pending.erase (pr);
5141 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5143 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5144 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5145 if (rv->region()->id () == (*rnote).first) {
5146 mrv->select_notes ((*rnote).second);
5147 selection->pending_midi_note_selection.erase(rnote);
5153 _summary->set_background_dirty ();
5157 Editor::region_view_removed ()
5159 _summary->set_background_dirty ();
5163 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5165 TrackViewList::const_iterator j = track_views.begin ();
5166 while (j != track_views.end()) {
5167 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5168 if (rtv && rtv->route() == r) {
5179 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5183 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5184 TimeAxisView* tv = axis_view_from_route (*i);
5194 Editor::suspend_route_redisplay ()
5197 _routes->suspend_redisplay();
5202 Editor::resume_route_redisplay ()
5205 _routes->redisplay(); // queue redisplay
5206 _routes->resume_redisplay();
5211 Editor::add_routes (RouteList& routes)
5213 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5215 RouteTimeAxisView *rtv;
5216 list<RouteTimeAxisView*> new_views;
5217 TrackViewList new_selection;
5218 bool from_scratch = (track_views.size() == 0);
5220 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5221 boost::shared_ptr<Route> route = (*x);
5223 if (route->is_auditioner() || route->is_monitor()) {
5227 DataType dt = route->input()->default_type();
5229 if (dt == ARDOUR::DataType::AUDIO) {
5230 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5231 rtv->set_route (route);
5232 } else if (dt == ARDOUR::DataType::MIDI) {
5233 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5234 rtv->set_route (route);
5236 throw unknown_type();
5239 new_views.push_back (rtv);
5240 track_views.push_back (rtv);
5241 new_selection.push_back (rtv);
5243 rtv->effective_gain_display ();
5245 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5246 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5249 if (new_views.size() > 0) {
5250 _routes->routes_added (new_views);
5251 _summary->routes_added (new_views);
5254 if (!from_scratch) {
5255 selection->tracks.clear();
5256 selection->add (new_selection);
5257 begin_selection_op_history();
5260 if (show_editor_mixer_when_tracks_arrive) {
5261 show_editor_mixer (true);
5264 editor_list_button.set_sensitive (true);
5268 Editor::timeaxisview_deleted (TimeAxisView *tv)
5270 if (tv == entered_track) {
5274 if (_session && _session->deletion_in_progress()) {
5275 /* the situation is under control */
5279 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5281 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5283 _routes->route_removed (tv);
5285 TimeAxisView::Children c = tv->get_child_list ();
5286 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5287 if (entered_track == i->get()) {
5292 /* remove it from the list of track views */
5294 TrackViewList::iterator i;
5296 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5297 i = track_views.erase (i);
5300 /* update whatever the current mixer strip is displaying, if revelant */
5302 boost::shared_ptr<Route> route;
5305 route = rtav->route ();
5308 if (current_mixer_strip && current_mixer_strip->route() == route) {
5310 TimeAxisView* next_tv;
5312 if (track_views.empty()) {
5314 } else if (i == track_views.end()) {
5315 next_tv = track_views.front();
5322 set_selected_mixer_strip (*next_tv);
5324 /* make the editor mixer strip go away setting the
5325 * button to inactive (which also unticks the menu option)
5328 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5334 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5336 if (apply_to_selection) {
5337 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5339 TrackSelection::iterator j = i;
5342 hide_track_in_display (*i, false);
5347 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5349 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5350 // this will hide the mixer strip
5351 set_selected_mixer_strip (*tv);
5354 _routes->hide_track_in_display (*tv);
5359 Editor::sync_track_view_list_and_routes ()
5361 track_views = TrackViewList (_routes->views ());
5363 _summary->set_background_dirty();
5364 _group_tabs->set_dirty ();
5366 return false; // do not call again (until needed)
5370 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5372 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5377 /** Find a RouteTimeAxisView by the ID of its route */
5379 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5381 RouteTimeAxisView* v;
5383 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5384 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5385 if(v->route()->id() == id) {
5395 Editor::fit_route_group (RouteGroup *g)
5397 TrackViewList ts = axis_views_from_routes (g->route_list ());
5402 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5404 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5407 _session->cancel_audition ();
5411 if (_session->is_auditioning()) {
5412 _session->cancel_audition ();
5413 if (r == last_audition_region) {
5418 _session->audition_region (r);
5419 last_audition_region = r;
5424 Editor::hide_a_region (boost::shared_ptr<Region> r)
5426 r->set_hidden (true);
5430 Editor::show_a_region (boost::shared_ptr<Region> r)
5432 r->set_hidden (false);
5436 Editor::audition_region_from_region_list ()
5438 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5442 Editor::hide_region_from_region_list ()
5444 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5448 Editor::show_region_in_region_list ()
5450 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5454 Editor::step_edit_status_change (bool yn)
5457 start_step_editing ();
5459 stop_step_editing ();
5464 Editor::start_step_editing ()
5466 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5470 Editor::stop_step_editing ()
5472 step_edit_connection.disconnect ();
5476 Editor::check_step_edit ()
5478 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5479 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5481 mtv->check_step_edit ();
5485 return true; // do it again, till we stop
5489 Editor::scroll_press (Direction dir)
5491 ++_scroll_callbacks;
5493 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5494 /* delay the first auto-repeat */
5500 scroll_backward (1);
5508 scroll_up_one_track ();
5512 scroll_down_one_track ();
5516 /* do hacky auto-repeat */
5517 if (!_scroll_connection.connected ()) {
5519 _scroll_connection = Glib::signal_timeout().connect (
5520 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5523 _scroll_callbacks = 0;
5530 Editor::scroll_release ()
5532 _scroll_connection.disconnect ();
5535 /** Queue a change for the Editor viewport x origin to follow the playhead */
5537 Editor::reset_x_origin_to_follow_playhead ()
5539 framepos_t const frame = playhead_cursor->current_frame ();
5541 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5543 if (_session->transport_speed() < 0) {
5545 if (frame > (current_page_samples() / 2)) {
5546 center_screen (frame-(current_page_samples()/2));
5548 center_screen (current_page_samples()/2);
5555 if (frame < leftmost_frame) {
5557 if (_session->transport_rolling()) {
5558 /* rolling; end up with the playhead at the right of the page */
5559 l = frame - current_page_samples ();
5561 /* not rolling: end up with the playhead 1/4 of the way along the page */
5562 l = frame - current_page_samples() / 4;
5566 if (_session->transport_rolling()) {
5567 /* rolling: end up with the playhead on the left of the page */
5570 /* not rolling: end up with the playhead 3/4 of the way along the page */
5571 l = frame - 3 * current_page_samples() / 4;
5579 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5585 Editor::super_rapid_screen_update ()
5587 if (!_session || !_session->engine().running()) {
5591 /* METERING / MIXER STRIPS */
5593 /* update track meters, if required */
5594 if (contents().is_mapped() && meters_running) {
5595 RouteTimeAxisView* rtv;
5596 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5597 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5598 rtv->fast_update ();
5603 /* and any current mixer strip */
5604 if (current_mixer_strip) {
5605 current_mixer_strip->fast_update ();
5608 /* PLAYHEAD AND VIEWPORT */
5610 framepos_t const frame = _session->audible_frame();
5612 /* There are a few reasons why we might not update the playhead / viewport stuff:
5614 * 1. we don't update things when there's a pending locate request, otherwise
5615 * when the editor requests a locate there is a chance that this method
5616 * will move the playhead before the locate request is processed, causing
5618 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5619 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5622 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5624 last_update_frame = frame;
5626 if (!_dragging_playhead) {
5627 playhead_cursor->set_position (frame);
5630 if (!_stationary_playhead) {
5632 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5633 /* We only do this if we aren't already
5634 handling a visual change (ie if
5635 pending_visual_change.being_handled is
5636 false) so that these requests don't stack
5637 up there are too many of them to handle in
5640 reset_x_origin_to_follow_playhead ();
5645 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5646 framepos_t const frame = playhead_cursor->current_frame ();
5647 double target = ((double)frame - (double)current_page_samples()/2.0);
5648 if (target <= 0.0) {
5651 // compare to EditorCursor::set_position()
5652 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5653 double const new_pos = sample_to_pixel_unrounded (target);
5654 if (rint (new_pos) != rint (old_pos)) {
5655 reset_x_origin (pixel_to_sample (floor (new_pos)));
5666 Editor::session_going_away ()
5668 _have_idled = false;
5670 _session_connections.drop_connections ();
5672 super_rapid_screen_update_connection.disconnect ();
5674 selection->clear ();
5675 cut_buffer->clear ();
5677 clicked_regionview = 0;
5678 clicked_axisview = 0;
5679 clicked_routeview = 0;
5680 entered_regionview = 0;
5682 last_update_frame = 0;
5685 playhead_cursor->hide ();
5687 /* rip everything out of the list displays */
5691 _route_groups->clear ();
5693 /* do this first so that deleting a track doesn't reset cms to null
5694 and thus cause a leak.
5697 if (current_mixer_strip) {
5698 if (current_mixer_strip->get_parent() != 0) {
5699 global_hpacker.remove (*current_mixer_strip);
5701 delete current_mixer_strip;
5702 current_mixer_strip = 0;
5705 /* delete all trackviews */
5707 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5710 track_views.clear ();
5712 nudge_clock->set_session (0);
5714 editor_list_button.set_active(false);
5715 editor_list_button.set_sensitive(false);
5717 /* clear tempo/meter rulers */
5718 remove_metric_marks ();
5720 clear_marker_display ();
5722 stop_step_editing ();
5726 /* get rid of any existing editor mixer strip */
5728 WindowTitle title(Glib::get_application_name());
5729 title += _("Editor");
5731 own_window()->set_title (title.get_string());
5734 SessionHandlePtr::session_going_away ();
5738 Editor::trigger_script (int i)
5740 LuaInstance::instance()-> call_action (i);
5744 Editor::set_script_action_name (int i, const std::string& n)
5746 string const a = string_compose (X_("script-action-%1"), i + 1);
5747 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5750 act->set_label (string_compose (_("Unset #%1"), i + 1));
5751 act->set_tooltip (_("no action bound"));
5752 act->set_sensitive (false);
5755 act->set_tooltip (n);
5756 act->set_sensitive (true);
5758 KeyEditor::UpdateBindings ();
5762 Editor::show_editor_list (bool yn)
5765 _the_notebook.show ();
5767 _the_notebook.hide ();
5772 Editor::change_region_layering_order (bool from_context_menu)
5774 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5776 if (!clicked_routeview) {
5777 if (layering_order_editor) {
5778 layering_order_editor->hide ();
5783 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5789 boost::shared_ptr<Playlist> pl = track->playlist();
5795 if (layering_order_editor == 0) {
5796 layering_order_editor = new RegionLayeringOrderEditor (*this);
5799 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5800 layering_order_editor->maybe_present ();
5804 Editor::update_region_layering_order_editor ()
5806 if (layering_order_editor && layering_order_editor->is_visible ()) {
5807 change_region_layering_order (true);
5812 Editor::setup_fade_images ()
5814 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5815 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5816 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5817 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5818 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5820 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5821 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5822 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5823 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5824 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5826 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5827 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5828 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5829 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5830 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5832 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5833 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5834 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5835 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5836 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5840 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5842 Editor::action_menu_item (std::string const & name)
5844 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5847 return *manage (a->create_menu_item ());
5851 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5853 EventBox* b = manage (new EventBox);
5854 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5855 Label* l = manage (new Label (name));
5859 _the_notebook.append_page (widget, *b);
5863 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5865 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5866 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5869 if (ev->type == GDK_2BUTTON_PRESS) {
5871 /* double-click on a notebook tab shrinks or expands the notebook */
5873 if (_notebook_shrunk) {
5874 if (pre_notebook_shrink_pane_width) {
5875 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5877 _notebook_shrunk = false;
5879 pre_notebook_shrink_pane_width = edit_pane.get_position();
5881 /* this expands the LHS of the edit pane to cover the notebook
5882 PAGE but leaves the tabs visible.
5884 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5885 _notebook_shrunk = true;
5893 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5895 using namespace Menu_Helpers;
5897 MenuList& items = _control_point_context_menu.items ();
5900 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5901 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5902 if (!can_remove_control_point (item)) {
5903 items.back().set_sensitive (false);
5906 _control_point_context_menu.popup (event->button.button, event->button.time);
5910 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5912 using namespace Menu_Helpers;
5914 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5919 /* We need to get the selection here and pass it to the operations, since
5920 popping up the menu will cause a region leave event which clears
5921 entered_regionview. */
5923 MidiRegionView& mrv = note->region_view();
5924 const RegionSelection rs = get_regions_from_selection_and_entered ();
5925 const uint32_t sel_size = mrv.selection_size ();
5927 MenuList& items = _note_context_menu.items();
5931 items.push_back(MenuElem(_("Delete"),
5932 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5935 items.push_back(MenuElem(_("Edit..."),
5936 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5937 if (sel_size != 1) {
5938 items.back().set_sensitive (false);
5941 items.push_back(MenuElem(_("Transpose..."),
5942 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
5945 items.push_back(MenuElem(_("Legatize"),
5946 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5948 items.back().set_sensitive (false);
5951 items.push_back(MenuElem(_("Quantize..."),
5952 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5954 items.push_back(MenuElem(_("Remove Overlap"),
5955 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5957 items.back().set_sensitive (false);
5960 items.push_back(MenuElem(_("Transform..."),
5961 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5963 _note_context_menu.popup (event->button.button, event->button.time);
5967 Editor::zoom_vertical_modifier_released()
5969 _stepping_axis_view = 0;
5973 Editor::ui_parameter_changed (string parameter)
5975 if (parameter == "icon-set") {
5976 while (!_cursor_stack.empty()) {
5977 _cursor_stack.pop_back();
5979 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
5980 _cursor_stack.push_back(_cursors->grabber);
5981 } else if (parameter == "draggable-playhead") {
5982 if (_verbose_cursor) {
5983 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
5989 Editor::use_own_window (bool and_fill_it)
5991 bool new_window = !own_window();
5993 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
5995 if (win && new_window) {
5996 win->set_name ("EditorWindow");
5998 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6000 // win->signal_realize().connect (*this, &Editor::on_realize);
6001 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6002 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6003 win->set_data ("ardour-bindings", bindings);
6008 DisplaySuspender ds;
6009 contents().show_all ();
6011 /* XXX: this is a bit unfortunate; it would probably
6012 be nicer if we could just call show () above rather
6013 than needing the show_all ()
6016 /* re-hide stuff if necessary */
6017 editor_list_button_toggled ();
6018 parameter_changed ("show-summary");
6019 parameter_changed ("show-group-tabs");
6020 parameter_changed ("show-zoom-tools");
6022 /* now reset all audio_time_axis heights, because widgets might need
6028 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6029 tv = (static_cast<TimeAxisView*>(*i));
6030 tv->reset_height ();
6033 if (current_mixer_strip) {
6034 current_mixer_strip->hide_things ();
6035 current_mixer_strip->parameter_changed ("mixer-element-visibility");