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.h"
76 #include "ardour/route_group.h"
77 #include "ardour/session_playlists.h"
78 #include "ardour/tempo.h"
79 #include "ardour/utils.h"
80 #include "ardour/vca_manager.h"
81 #include "ardour/vca.h"
83 #include "canvas/debug.h"
84 #include "canvas/text.h"
86 #include "control_protocol/control_protocol.h"
89 #include "analysis_window.h"
90 #include "audio_clock.h"
91 #include "audio_region_view.h"
92 #include "audio_streamview.h"
93 #include "audio_time_axis.h"
94 #include "automation_time_axis.h"
95 #include "bundle_manager.h"
96 #include "crossfade_edit.h"
100 #include "editor_cursors.h"
101 #include "editor_drag.h"
102 #include "editor_group_tabs.h"
103 #include "editor_locations.h"
104 #include "editor_regions.h"
105 #include "editor_route_groups.h"
106 #include "editor_routes.h"
107 #include "editor_snapshots.h"
108 #include "editor_summary.h"
109 #include "export_report.h"
110 #include "global_port_matrix.h"
111 #include "gui_object.h"
112 #include "gui_thread.h"
113 #include "keyboard.h"
114 #include "keyeditor.h"
115 #include "luainstance.h"
117 #include "midi_region_view.h"
118 #include "midi_time_axis.h"
119 #include "mixer_strip.h"
120 #include "mixer_ui.h"
121 #include "mouse_cursors.h"
122 #include "note_base.h"
123 #include "playlist_selector.h"
124 #include "public_editor.h"
125 #include "quantize_dialog.h"
126 #include "region_layering_order_editor.h"
127 #include "rgb_macros.h"
128 #include "rhythm_ferret.h"
129 #include "selection.h"
130 #include "simple_progress_dialog.h"
132 #include "tempo_lines.h"
133 #include "time_axis_view.h"
135 #include "tooltips.h"
136 #include "ui_config.h"
138 #include "vca_time_axis.h"
139 #include "verbose_cursor.h"
144 using namespace ARDOUR;
145 using namespace ARDOUR_UI_UTILS;
148 using namespace Glib;
149 using namespace Gtkmm2ext;
150 using namespace Editing;
152 using PBD::internationalize;
154 using Gtkmm2ext::Keyboard;
156 double Editor::timebar_height = 15.0;
158 static const gchar *_snap_type_strings[] = {
192 static const gchar *_snap_mode_strings[] = {
199 static const gchar *_edit_point_strings[] = {
206 static const gchar *_edit_mode_strings[] = {
214 static const gchar *_zoom_focus_strings[] = {
224 #ifdef USE_RUBBERBAND
225 static const gchar *_rb_opt_strings[] = {
228 N_("Balanced multitimbral mixture"),
229 N_("Unpitched percussion with stable notes"),
230 N_("Crisp monophonic instrumental"),
231 N_("Unpitched solo percussion"),
232 N_("Resample without preserving pitch"),
237 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
240 : PublicEditor (global_hpacker)
241 , editor_mixer_strip_width (Wide)
242 , constructed (false)
243 , _playlist_selector (0)
244 , no_save_visual (false)
246 , samples_per_pixel (2048)
247 , zoom_focus (ZoomFocusPlayhead)
248 , mouse_mode (MouseObject)
249 , pre_internal_snap_type (SnapToBeat)
250 , pre_internal_snap_mode (SnapOff)
251 , internal_snap_type (SnapToBeat)
252 , internal_snap_mode (SnapOff)
253 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
254 , _notebook_shrunk (false)
255 , location_marker_color (0)
256 , location_range_color (0)
257 , location_loop_color (0)
258 , location_punch_color (0)
259 , location_cd_marker_color (0)
261 , _show_marker_lines (false)
262 , clicked_axisview (0)
263 , clicked_routeview (0)
264 , clicked_regionview (0)
265 , clicked_selection (0)
266 , clicked_control_point (0)
267 , button_release_can_deselect (true)
268 , _mouse_changed_selection (false)
269 , region_edit_menu_split_item (0)
270 , region_edit_menu_split_multichannel_item (0)
271 , track_region_edit_playlist_menu (0)
272 , track_edit_playlist_submenu (0)
273 , track_selection_edit_playlist_submenu (0)
274 , _popup_region_menu_item (0)
276 , _track_canvas_viewport (0)
277 , within_track_canvas (false)
278 , _verbose_cursor (0)
282 , range_marker_group (0)
283 , transport_marker_group (0)
284 , cd_marker_group (0)
285 , _time_markers_group (0)
286 , hv_scroll_group (0)
288 , cursor_scroll_group (0)
289 , no_scroll_group (0)
290 , _trackview_group (0)
291 , _drag_motion_group (0)
292 , _canvas_drop_zone (0)
293 , no_ruler_shown_update (false)
294 , ruler_grabbed_widget (0)
296 , minsec_mark_interval (0)
297 , minsec_mark_modulo (0)
299 , timecode_mark_modulo (0)
300 , timecode_nmarks (0)
301 , _samples_ruler_interval (0)
304 , bbt_bar_helper_on (0)
305 , bbt_accent_modulo (0)
310 , visible_timebars (0)
311 , editor_ruler_menu (0)
315 , range_marker_bar (0)
316 , transport_marker_bar (0)
318 , minsec_label (_("Mins:Secs"))
319 , bbt_label (_("Bars:Beats"))
320 , timecode_label (_("Timecode"))
321 , samples_label (_("Samples"))
322 , tempo_label (_("Tempo"))
323 , meter_label (_("Meter"))
324 , mark_label (_("Location Markers"))
325 , range_mark_label (_("Range Markers"))
326 , transport_mark_label (_("Loop/Punch Ranges"))
327 , cd_mark_label (_("CD Markers"))
328 , videotl_label (_("Video Timeline"))
330 , playhead_cursor (0)
331 , edit_packer (4, 4, true)
332 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
333 , horizontal_adjustment (0.0, 0.0, 1e16)
334 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
335 , controls_layout (unused_adjustment, vertical_adjustment)
336 , _scroll_callbacks (0)
337 , _visible_canvas_width (0)
338 , _visible_canvas_height (0)
339 , _full_canvas_height (0)
340 , edit_controls_left_menu (0)
341 , edit_controls_right_menu (0)
342 , last_update_frame (0)
343 , cut_buffer_start (0)
344 , cut_buffer_length (0)
345 , button_bindings (0)
349 , current_interthread_info (0)
350 , analysis_window (0)
351 , select_new_marker (false)
353 , scrubbing_direction (0)
354 , scrub_reversals (0)
355 , scrub_reverse_distance (0)
356 , have_pending_keyboard_selection (false)
357 , pending_keyboard_selection_start (0)
358 , _snap_type (SnapToBeat)
359 , _snap_mode (SnapOff)
360 , snap_threshold (5.0)
361 , ignore_gui_changes (false)
362 , _drags (new DragManager (this))
364 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
365 , _dragging_playhead (false)
366 , _dragging_edit_point (false)
367 , _show_measures (true)
368 , _follow_playhead (true)
369 , _stationary_playhead (false)
372 , global_rect_group (0)
373 , time_line_group (0)
374 , tempo_marker_menu (0)
375 , meter_marker_menu (0)
377 , range_marker_menu (0)
378 , transport_marker_menu (0)
379 , new_transport_marker_menu (0)
381 , marker_menu_item (0)
382 , bbt_beat_subdivision (4)
383 , _visible_track_count (-1)
384 , toolbar_selection_clock_table (2,3)
385 , automation_mode_button (_("mode"))
386 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
387 , selection (new Selection (this))
388 , cut_buffer (new Selection (this))
389 , _selection_memento (new SelectionMemento())
390 , _all_region_actions_sensitized (false)
391 , _ignore_region_action (false)
392 , _last_region_menu_was_main (false)
393 , _ignore_follow_edits (false)
394 , cd_marker_bar_drag_rect (0)
395 , range_bar_drag_rect (0)
396 , transport_bar_drag_rect (0)
397 , transport_bar_range_rect (0)
398 , transport_bar_preroll_rect (0)
399 , transport_bar_postroll_rect (0)
400 , transport_loop_range_rect (0)
401 , transport_punch_range_rect (0)
402 , transport_punchin_line (0)
403 , transport_punchout_line (0)
404 , transport_preroll_rect (0)
405 , transport_postroll_rect (0)
407 , rubberband_rect (0)
413 , autoscroll_horizontal_allowed (false)
414 , autoscroll_vertical_allowed (false)
416 , autoscroll_widget (0)
417 , show_gain_after_trim (false)
418 , selection_op_cmd_depth (0)
419 , selection_op_history_it (0)
420 , no_save_instant (false)
422 , current_mixer_strip (0)
423 , show_editor_mixer_when_tracks_arrive (false)
424 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
425 , current_stepping_trackview (0)
426 , last_track_height_step_timestamp (0)
428 , entered_regionview (0)
429 , clear_entered_track (false)
430 , _edit_point (EditAtMouse)
431 , meters_running (false)
433 , _have_idled (false)
434 , resize_idle_id (-1)
435 , _pending_resize_amount (0)
436 , _pending_resize_view (0)
437 , _pending_locate_request (false)
438 , _pending_initial_locate (false)
442 , layering_order_editor (0)
443 , _last_cut_copy_source_track (0)
444 , _region_selection_change_updates_region_list (true)
446 , _following_mixer_selection (false)
447 , _control_point_toggled_on_press (false)
448 , _stepping_axis_view (0)
449 , quantize_dialog (0)
450 , _main_menu_disabler (0)
451 , myactions (X_("editor"))
453 /* we are a singleton */
455 PublicEditor::_instance = this;
459 last_event_time.tv_sec = 0;
460 last_event_time.tv_usec = 0;
462 selection_op_history.clear();
465 snap_type_strings = I18N (_snap_type_strings);
466 snap_mode_strings = I18N (_snap_mode_strings);
467 zoom_focus_strings = I18N (_zoom_focus_strings);
468 edit_mode_strings = I18N (_edit_mode_strings);
469 edit_point_strings = I18N (_edit_point_strings);
470 #ifdef USE_RUBBERBAND
471 rb_opt_strings = I18N (_rb_opt_strings);
475 build_edit_mode_menu();
476 build_zoom_focus_menu();
477 build_track_count_menu();
478 build_snap_mode_menu();
479 build_snap_type_menu();
480 build_edit_point_menu();
482 location_marker_color = UIConfiguration::instance().color ("location marker");
483 location_range_color = UIConfiguration::instance().color ("location range");
484 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
485 location_loop_color = UIConfiguration::instance().color ("location loop");
486 location_punch_color = UIConfiguration::instance().color ("location punch");
488 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
490 TimeAxisView::setup_sizes ();
491 ArdourMarker::setup_sizes (timebar_height);
492 TempoCurve::setup_sizes (timebar_height);
494 bbt_label.set_name ("EditorRulerLabel");
495 bbt_label.set_size_request (-1, (int)timebar_height);
496 bbt_label.set_alignment (1.0, 0.5);
497 bbt_label.set_padding (5,0);
499 bbt_label.set_no_show_all();
500 minsec_label.set_name ("EditorRulerLabel");
501 minsec_label.set_size_request (-1, (int)timebar_height);
502 minsec_label.set_alignment (1.0, 0.5);
503 minsec_label.set_padding (5,0);
504 minsec_label.hide ();
505 minsec_label.set_no_show_all();
506 timecode_label.set_name ("EditorRulerLabel");
507 timecode_label.set_size_request (-1, (int)timebar_height);
508 timecode_label.set_alignment (1.0, 0.5);
509 timecode_label.set_padding (5,0);
510 timecode_label.hide ();
511 timecode_label.set_no_show_all();
512 samples_label.set_name ("EditorRulerLabel");
513 samples_label.set_size_request (-1, (int)timebar_height);
514 samples_label.set_alignment (1.0, 0.5);
515 samples_label.set_padding (5,0);
516 samples_label.hide ();
517 samples_label.set_no_show_all();
519 tempo_label.set_name ("EditorRulerLabel");
520 tempo_label.set_size_request (-1, (int)timebar_height);
521 tempo_label.set_alignment (1.0, 0.5);
522 tempo_label.set_padding (5,0);
524 tempo_label.set_no_show_all();
526 meter_label.set_name ("EditorRulerLabel");
527 meter_label.set_size_request (-1, (int)timebar_height);
528 meter_label.set_alignment (1.0, 0.5);
529 meter_label.set_padding (5,0);
531 meter_label.set_no_show_all();
533 if (Profile->get_trx()) {
534 mark_label.set_text (_("Markers"));
536 mark_label.set_name ("EditorRulerLabel");
537 mark_label.set_size_request (-1, (int)timebar_height);
538 mark_label.set_alignment (1.0, 0.5);
539 mark_label.set_padding (5,0);
541 mark_label.set_no_show_all();
543 cd_mark_label.set_name ("EditorRulerLabel");
544 cd_mark_label.set_size_request (-1, (int)timebar_height);
545 cd_mark_label.set_alignment (1.0, 0.5);
546 cd_mark_label.set_padding (5,0);
547 cd_mark_label.hide();
548 cd_mark_label.set_no_show_all();
550 videotl_bar_height = 4;
551 videotl_label.set_name ("EditorRulerLabel");
552 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
553 videotl_label.set_alignment (1.0, 0.5);
554 videotl_label.set_padding (5,0);
555 videotl_label.hide();
556 videotl_label.set_no_show_all();
558 range_mark_label.set_name ("EditorRulerLabel");
559 range_mark_label.set_size_request (-1, (int)timebar_height);
560 range_mark_label.set_alignment (1.0, 0.5);
561 range_mark_label.set_padding (5,0);
562 range_mark_label.hide();
563 range_mark_label.set_no_show_all();
565 transport_mark_label.set_name ("EditorRulerLabel");
566 transport_mark_label.set_size_request (-1, (int)timebar_height);
567 transport_mark_label.set_alignment (1.0, 0.5);
568 transport_mark_label.set_padding (5,0);
569 transport_mark_label.hide();
570 transport_mark_label.set_no_show_all();
572 initialize_canvas ();
574 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
576 _summary = new EditorSummary (this);
578 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
579 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
581 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
583 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
584 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
586 edit_controls_vbox.set_spacing (0);
587 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
588 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
590 HBox* h = manage (new HBox);
591 _group_tabs = new EditorGroupTabs (this);
592 if (!ARDOUR::Profile->get_trx()) {
593 h->pack_start (*_group_tabs, PACK_SHRINK);
595 h->pack_start (edit_controls_vbox);
596 controls_layout.add (*h);
598 controls_layout.set_name ("EditControlsBase");
599 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
600 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
601 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
603 _cursors = new MouseCursors;
604 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
605 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
607 /* Push default cursor to ever-present bottom of cursor stack. */
608 push_canvas_cursor(_cursors->grabber);
610 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
612 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
613 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
614 pad_line_1->set_outline_color (0xFF0000FF);
620 edit_packer.set_col_spacings (0);
621 edit_packer.set_row_spacings (0);
622 edit_packer.set_homogeneous (false);
623 edit_packer.set_border_width (0);
624 edit_packer.set_name ("EditorWindow");
626 time_bars_event_box.add (time_bars_vbox);
627 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
628 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
630 /* labels for the time bars */
631 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
633 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
635 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
637 bottom_hbox.set_border_width (2);
638 bottom_hbox.set_spacing (3);
640 _route_groups = new EditorRouteGroups (this);
641 _routes = new EditorRoutes (this);
642 _regions = new EditorRegions (this);
643 _snapshots = new EditorSnapshots (this);
644 _locations = new EditorLocations (this);
646 /* these are static location signals */
648 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
649 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
650 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
652 add_notebook_page (_("Regions"), _regions->widget ());
653 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
654 add_notebook_page (_("Snapshots"), _snapshots->widget ());
655 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
656 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
658 _the_notebook.set_show_tabs (true);
659 _the_notebook.set_scrollable (true);
660 _the_notebook.popup_disable ();
661 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
662 _the_notebook.show_all ();
664 _notebook_shrunk = false;
667 /* Pick up some settings we need to cache, early */
669 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
672 if (settings && (prop = settings->property ("notebook-shrunk"))) {
673 _notebook_shrunk = string_is_affirmative (prop->value ());
676 editor_summary_pane.add (edit_packer);
678 Button* summary_arrows_left_left = manage (new Button);
679 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
680 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
681 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
683 Button* summary_arrows_left_right = manage (new Button);
684 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
685 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
686 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
688 VBox* summary_arrows_left = manage (new VBox);
689 summary_arrows_left->pack_start (*summary_arrows_left_left);
690 summary_arrows_left->pack_start (*summary_arrows_left_right);
692 Button* summary_arrows_right_up = manage (new Button);
693 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
694 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
695 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
697 Button* summary_arrows_right_down = manage (new Button);
698 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
699 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
700 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
702 VBox* summary_arrows_right = manage (new VBox);
703 summary_arrows_right->pack_start (*summary_arrows_right_up);
704 summary_arrows_right->pack_start (*summary_arrows_right_down);
706 Frame* summary_frame = manage (new Frame);
707 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
709 summary_frame->add (*_summary);
710 summary_frame->show ();
712 _summary_hbox.pack_start (*summary_arrows_left, false, false);
713 _summary_hbox.pack_start (*summary_frame, true, true);
714 _summary_hbox.pack_start (*summary_arrows_right, false, false);
716 if (!ARDOUR::Profile->get_trx()) {
717 editor_summary_pane.add (_summary_hbox);
720 edit_pane.add (editor_summary_pane);
721 if (!ARDOUR::Profile->get_trx()) {
722 edit_pane.add (_the_notebook);
725 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
726 edit_pane.set_child_minsize (_the_notebook, 30); /* rough guess at width of notebook tabs */
727 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
734 if (!settings || ((prop = settings->property ("edit-horizontal-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
735 /* initial allocation is 90% to canvas, 10% to notebook */
736 edit_pane.set_divider (0, 0.90);
738 edit_pane.set_divider (0, fract);
741 if (!settings || ((prop = settings->property ("edit-vertical-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
742 /* initial allocation is 90% to canvas, 10% to summary */
743 editor_summary_pane.set_divider (0, 0.90);
746 editor_summary_pane.set_divider (0, fract);
750 top_hbox.pack_start (toolbar_frame);
752 HBox *hbox = manage (new HBox);
753 hbox->pack_start (edit_pane, true, true);
755 global_vpacker.pack_start (top_hbox, false, false);
756 global_vpacker.pack_start (*hbox, true, true);
757 global_hpacker.pack_start (global_vpacker, true, true);
759 /* need to show the "contents" widget so that notebook will show if tab is switched to
762 global_hpacker.show ();
764 /* register actions now so that set_state() can find them and set toggles/checks etc */
771 _playlist_selector = new PlaylistSelector();
772 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
774 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
778 nudge_forward_button.set_name ("nudge button");
779 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
781 nudge_backward_button.set_name ("nudge button");
782 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
784 fade_context_menu.set_name ("ArdourContextMenu");
786 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
788 /* allow external control surfaces/protocols to do various things */
790 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
791 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
792 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
793 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
794 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
795 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
796 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
797 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
798 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
799 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
800 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
801 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
802 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
803 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
805 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
806 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
807 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
808 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
809 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
811 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
815 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
817 /* problematic: has to return a value and thus cannot be x-thread */
819 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
821 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
822 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
824 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
826 _ignore_region_action = false;
827 _last_region_menu_was_main = false;
828 _popup_region_menu_item = 0;
830 _ignore_follow_edits = false;
832 _show_marker_lines = false;
834 /* Button bindings */
836 button_bindings = new Bindings ("editor-mouse");
838 XMLNode* node = button_settings();
840 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
841 button_bindings->load_operation (**i);
847 /* grab current parameter state */
848 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
849 UIConfiguration::instance().map_parameters (pc);
851 setup_fade_images ();
853 LuaInstance::instance(); // instantiate
854 LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &Editor::set_script_action_name));
861 delete button_bindings;
863 delete _route_groups;
864 delete _track_canvas_viewport;
867 delete quantize_dialog;
873 delete _playlist_selector;
875 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
881 Editor::button_settings () const
883 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
884 XMLNode* node = find_named_node (*settings, X_("Buttons"));
887 node = new XMLNode (X_("Buttons"));
894 Editor::get_smart_mode () const
896 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
900 Editor::catch_vanishing_regionview (RegionView *rv)
902 /* note: the selection will take care of the vanishing
903 audioregionview by itself.
906 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
910 if (clicked_regionview == rv) {
911 clicked_regionview = 0;
914 if (entered_regionview == rv) {
915 set_entered_regionview (0);
918 if (!_all_region_actions_sensitized) {
919 sensitize_all_region_actions (true);
924 Editor::set_entered_regionview (RegionView* rv)
926 if (rv == entered_regionview) {
930 if (entered_regionview) {
931 entered_regionview->exited ();
934 entered_regionview = rv;
936 if (entered_regionview != 0) {
937 entered_regionview->entered ();
940 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
941 /* This RegionView entry might have changed what region actions
942 are allowed, so sensitize them all in case a key is pressed.
944 sensitize_all_region_actions (true);
949 Editor::set_entered_track (TimeAxisView* tav)
952 entered_track->exited ();
958 entered_track->entered ();
963 Editor::instant_save ()
965 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
970 _session->add_instant_xml(get_state());
972 Config->add_instant_xml(get_state());
977 Editor::control_vertical_zoom_in_all ()
979 tav_zoom_smooth (false, true);
983 Editor::control_vertical_zoom_out_all ()
985 tav_zoom_smooth (true, true);
989 Editor::control_vertical_zoom_in_selected ()
991 tav_zoom_smooth (false, false);
995 Editor::control_vertical_zoom_out_selected ()
997 tav_zoom_smooth (true, false);
1001 Editor::control_view (uint32_t view)
1003 goto_visual_state (view);
1007 Editor::control_unselect ()
1009 selection->clear_tracks ();
1013 Editor::control_select (PresentationInfo::global_order_t global_order, Selection::Operation op)
1015 /* handles the (static) signal from the ControlProtocol class that
1016 * requests setting the selected track to a given RID
1023 PresentationInfo::Flag select_flags;
1025 if (global_order & ~0xffffffff) {
1026 /* some flags are set, so the PresentationInfo constructor
1029 select_flags = PresentationInfo::Flag (0);
1031 /* no type flags set in the global order ID, so assume caller
1032 * wants to select a Route
1034 select_flags = PresentationInfo::Route;
1037 PresentationInfo pi (global_order, select_flags);
1038 boost::shared_ptr<Stripable> s = _session->get_remote_nth_stripable (pi.order(), pi.flags());
1040 /* selected object may not be a Route */
1042 boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route> (s);
1048 TimeAxisView* tav = axis_view_from_route (r);
1052 case Selection::Add:
1053 selection->add (tav);
1055 case Selection::Toggle:
1056 selection->toggle (tav);
1058 case Selection::Extend:
1060 case Selection::Set:
1061 selection->set (tav);
1065 selection->clear_tracks ();
1070 Editor::control_step_tracks_up ()
1072 scroll_tracks_up_line ();
1076 Editor::control_step_tracks_down ()
1078 scroll_tracks_down_line ();
1082 Editor::control_scroll (float fraction)
1084 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1090 double step = fraction * current_page_samples();
1093 _control_scroll_target is an optional<T>
1095 it acts like a pointer to an framepos_t, with
1096 a operator conversion to boolean to check
1097 that it has a value could possibly use
1098 playhead_cursor->current_frame to store the
1099 value and a boolean in the class to know
1100 when it's out of date
1103 if (!_control_scroll_target) {
1104 _control_scroll_target = _session->transport_frame();
1105 _dragging_playhead = true;
1108 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1109 *_control_scroll_target = 0;
1110 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1111 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1113 *_control_scroll_target += (framepos_t) trunc (step);
1116 /* move visuals, we'll catch up with it later */
1118 playhead_cursor->set_position (*_control_scroll_target);
1119 UpdateAllTransportClocks (*_control_scroll_target);
1121 if (*_control_scroll_target > (current_page_samples() / 2)) {
1122 /* try to center PH in window */
1123 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1129 Now we do a timeout to actually bring the session to the right place
1130 according to the playhead. This is to avoid reading disk buffers on every
1131 call to control_scroll, which is driven by ScrollTimeline and therefore
1132 probably by a control surface wheel which can generate lots of events.
1134 /* cancel the existing timeout */
1136 control_scroll_connection.disconnect ();
1138 /* add the next timeout */
1140 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1144 Editor::deferred_control_scroll (framepos_t /*target*/)
1146 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1147 // reset for next stream
1148 _control_scroll_target = boost::none;
1149 _dragging_playhead = false;
1154 Editor::access_action (std::string action_group, std::string action_item)
1160 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1163 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1171 Editor::on_realize ()
1175 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1176 start_lock_event_timing ();
1181 Editor::start_lock_event_timing ()
1183 /* check if we should lock the GUI every 30 seconds */
1185 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1189 Editor::generic_event_handler (GdkEvent* ev)
1192 case GDK_BUTTON_PRESS:
1193 case GDK_BUTTON_RELEASE:
1194 case GDK_MOTION_NOTIFY:
1196 case GDK_KEY_RELEASE:
1197 if (contents().is_mapped()) {
1198 gettimeofday (&last_event_time, 0);
1202 case GDK_LEAVE_NOTIFY:
1203 switch (ev->crossing.detail) {
1204 case GDK_NOTIFY_UNKNOWN:
1205 case GDK_NOTIFY_INFERIOR:
1206 case GDK_NOTIFY_ANCESTOR:
1208 case GDK_NOTIFY_VIRTUAL:
1209 case GDK_NOTIFY_NONLINEAR:
1210 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1211 /* leaving window, so reset focus, thus ending any and
1212 all text entry operations.
1214 reset_focus (&contents());
1227 Editor::lock_timeout_callback ()
1229 struct timeval now, delta;
1231 gettimeofday (&now, 0);
1233 timersub (&now, &last_event_time, &delta);
1235 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1237 /* don't call again. Returning false will effectively
1238 disconnect us from the timer callback.
1240 unlock() will call start_lock_event_timing() to get things
1250 Editor::map_position_change (framepos_t frame)
1252 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1254 if (_session == 0) {
1258 if (_follow_playhead) {
1259 center_screen (frame);
1262 playhead_cursor->set_position (frame);
1266 Editor::center_screen (framepos_t frame)
1268 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1270 /* if we're off the page, then scroll.
1273 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1274 center_screen_internal (frame, page);
1279 Editor::center_screen_internal (framepos_t frame, float page)
1284 frame -= (framepos_t) page;
1289 reset_x_origin (frame);
1294 Editor::update_title ()
1296 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1298 if (!own_window()) {
1303 bool dirty = _session->dirty();
1305 string session_name;
1307 if (_session->snap_name() != _session->name()) {
1308 session_name = _session->snap_name();
1310 session_name = _session->name();
1314 session_name = "*" + session_name;
1317 WindowTitle title(session_name);
1318 title += S_("Window|Editor");
1319 title += Glib::get_application_name();
1320 own_window()->set_title (title.get_string());
1322 /* ::session_going_away() will have taken care of it */
1327 Editor::set_session (Session *t)
1329 SessionHandlePtr::set_session (t);
1335 _playlist_selector->set_session (_session);
1336 nudge_clock->set_session (_session);
1337 _summary->set_session (_session);
1338 _group_tabs->set_session (_session);
1339 _route_groups->set_session (_session);
1340 _regions->set_session (_session);
1341 _snapshots->set_session (_session);
1342 _routes->set_session (_session);
1343 _locations->set_session (_session);
1345 if (rhythm_ferret) {
1346 rhythm_ferret->set_session (_session);
1349 if (analysis_window) {
1350 analysis_window->set_session (_session);
1354 sfbrowser->set_session (_session);
1357 compute_fixed_ruler_scale ();
1359 /* Make sure we have auto loop and auto punch ranges */
1361 Location* loc = _session->locations()->auto_loop_location();
1363 loc->set_name (_("Loop"));
1366 loc = _session->locations()->auto_punch_location();
1369 loc->set_name (_("Punch"));
1372 refresh_location_display ();
1374 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1375 the selected Marker; this needs the LocationMarker list to be available.
1377 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1378 set_state (*node, Stateful::loading_state_version);
1380 /* catch up with the playhead */
1382 _session->request_locate (playhead_cursor->current_frame ());
1383 _pending_initial_locate = true;
1387 /* These signals can all be emitted by a non-GUI thread. Therefore the
1388 handlers for them must not attempt to directly interact with the GUI,
1389 but use PBD::Signal<T>::connect() which accepts an event loop
1390 ("context") where the handler will be asked to run.
1393 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1394 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1395 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1396 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1397 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1398 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1399 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1400 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::marker_position_changed, this), gui_context());
1401 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1402 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1403 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1404 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1405 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1406 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1407 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1409 playhead_cursor->show ();
1411 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1412 Config->map_parameters (pc);
1413 _session->config.map_parameters (pc);
1415 restore_ruler_visibility ();
1416 //tempo_map_changed (PropertyChange (0));
1417 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1419 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1420 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1423 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1424 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1427 switch (_snap_type) {
1428 case SnapToRegionStart:
1429 case SnapToRegionEnd:
1430 case SnapToRegionSync:
1431 case SnapToRegionBoundary:
1432 build_region_boundary_cache ();
1439 /* register for undo history */
1440 _session->register_with_memento_command_factory(id(), this);
1441 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1443 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1445 LuaInstance::instance()->set_session(_session);
1447 start_updating_meters ();
1451 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1453 if (a->get_name() == "RegionMenu") {
1454 /* When the main menu's region menu is opened, we setup the actions so that they look right
1455 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1456 so we resensitize all region actions when the entered regionview or the region selection
1457 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1458 happens after the region context menu is opened. So we set a flag here, too.
1462 sensitize_the_right_region_actions ();
1463 _last_region_menu_was_main = true;
1468 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1470 using namespace Menu_Helpers;
1472 void (Editor::*emf)(FadeShape);
1473 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1476 images = &_xfade_in_images;
1477 emf = &Editor::set_fade_in_shape;
1479 images = &_xfade_out_images;
1480 emf = &Editor::set_fade_out_shape;
1485 _("Linear (for highly correlated material)"),
1486 *(*images)[FadeLinear],
1487 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1491 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1495 _("Constant power"),
1496 *(*images)[FadeConstantPower],
1497 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1500 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1505 *(*images)[FadeSymmetric],
1506 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1510 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1515 *(*images)[FadeSlow],
1516 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1519 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1524 *(*images)[FadeFast],
1525 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1528 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1531 /** Pop up a context menu for when the user clicks on a start crossfade */
1533 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1535 using namespace Menu_Helpers;
1536 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1541 MenuList& items (xfade_in_context_menu.items());
1544 if (arv->audio_region()->fade_in_active()) {
1545 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1547 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1550 items.push_back (SeparatorElem());
1551 fill_xfade_menu (items, true);
1553 xfade_in_context_menu.popup (button, time);
1556 /** Pop up a context menu for when the user clicks on an end crossfade */
1558 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1560 using namespace Menu_Helpers;
1561 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1566 MenuList& items (xfade_out_context_menu.items());
1569 if (arv->audio_region()->fade_out_active()) {
1570 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1572 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1575 items.push_back (SeparatorElem());
1576 fill_xfade_menu (items, false);
1578 xfade_out_context_menu.popup (button, time);
1582 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1584 using namespace Menu_Helpers;
1585 Menu* (Editor::*build_menu_function)();
1588 switch (item_type) {
1590 case RegionViewName:
1591 case RegionViewNameHighlight:
1592 case LeftFrameHandle:
1593 case RightFrameHandle:
1594 if (with_selection) {
1595 build_menu_function = &Editor::build_track_selection_context_menu;
1597 build_menu_function = &Editor::build_track_region_context_menu;
1602 if (with_selection) {
1603 build_menu_function = &Editor::build_track_selection_context_menu;
1605 build_menu_function = &Editor::build_track_context_menu;
1610 if (clicked_routeview->track()) {
1611 build_menu_function = &Editor::build_track_context_menu;
1613 build_menu_function = &Editor::build_track_bus_context_menu;
1618 /* probably shouldn't happen but if it does, we don't care */
1622 menu = (this->*build_menu_function)();
1623 menu->set_name ("ArdourContextMenu");
1625 /* now handle specific situations */
1627 switch (item_type) {
1629 case RegionViewName:
1630 case RegionViewNameHighlight:
1631 case LeftFrameHandle:
1632 case RightFrameHandle:
1633 if (!with_selection) {
1634 if (region_edit_menu_split_item) {
1635 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1636 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1638 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1641 if (region_edit_menu_split_multichannel_item) {
1642 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1643 region_edit_menu_split_multichannel_item->set_sensitive (true);
1645 region_edit_menu_split_multichannel_item->set_sensitive (false);
1658 /* probably shouldn't happen but if it does, we don't care */
1662 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1664 /* Bounce to disk */
1666 using namespace Menu_Helpers;
1667 MenuList& edit_items = menu->items();
1669 edit_items.push_back (SeparatorElem());
1671 switch (clicked_routeview->audio_track()->freeze_state()) {
1672 case AudioTrack::NoFreeze:
1673 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1676 case AudioTrack::Frozen:
1677 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1680 case AudioTrack::UnFrozen:
1681 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1687 if (item_type == StreamItem && clicked_routeview) {
1688 clicked_routeview->build_underlay_menu(menu);
1691 /* When the region menu is opened, we setup the actions so that they look right
1694 sensitize_the_right_region_actions ();
1695 _last_region_menu_was_main = false;
1697 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1698 menu->popup (button, time);
1702 Editor::build_track_context_menu ()
1704 using namespace Menu_Helpers;
1706 MenuList& edit_items = track_context_menu.items();
1709 add_dstream_context_items (edit_items);
1710 return &track_context_menu;
1714 Editor::build_track_bus_context_menu ()
1716 using namespace Menu_Helpers;
1718 MenuList& edit_items = track_context_menu.items();
1721 add_bus_context_items (edit_items);
1722 return &track_context_menu;
1726 Editor::build_track_region_context_menu ()
1728 using namespace Menu_Helpers;
1729 MenuList& edit_items = track_region_context_menu.items();
1732 /* we've just cleared the track region context menu, so the menu that these
1733 two items were on will have disappeared; stop them dangling.
1735 region_edit_menu_split_item = 0;
1736 region_edit_menu_split_multichannel_item = 0;
1738 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1741 boost::shared_ptr<Track> tr;
1742 boost::shared_ptr<Playlist> pl;
1744 if ((tr = rtv->track())) {
1745 add_region_context_items (edit_items, tr);
1749 add_dstream_context_items (edit_items);
1751 return &track_region_context_menu;
1755 Editor::loudness_analyze_region_selection ()
1760 Selection& s (PublicEditor::instance ().get_selection ());
1761 RegionSelection ars = s.regions;
1762 ARDOUR::AnalysisGraph ag (_session);
1763 framecnt_t total_work = 0;
1765 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1766 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1770 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1773 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1774 total_work += arv->region ()->length ();
1777 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1779 ag.set_total_frames (total_work);
1780 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1783 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1784 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1788 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1792 ag.analyze_region (ar);
1795 if (!ag.canceled ()) {
1796 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1802 Editor::loudness_analyze_range_selection ()
1807 Selection& s (PublicEditor::instance ().get_selection ());
1808 TimeSelection ts = s.time;
1809 ARDOUR::AnalysisGraph ag (_session);
1810 framecnt_t total_work = 0;
1812 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1813 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1817 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1821 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1822 total_work += j->length ();
1826 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1828 ag.set_total_frames (total_work);
1829 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1832 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1833 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1837 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1841 ag.analyze_range (rui->route (), pl, ts);
1844 if (!ag.canceled ()) {
1845 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1851 Editor::spectral_analyze_region_selection ()
1853 if (analysis_window == 0) {
1854 analysis_window = new AnalysisWindow();
1857 analysis_window->set_session(_session);
1859 analysis_window->show_all();
1862 analysis_window->set_regionmode();
1863 analysis_window->analyze();
1865 analysis_window->present();
1869 Editor::spectral_analyze_range_selection()
1871 if (analysis_window == 0) {
1872 analysis_window = new AnalysisWindow();
1875 analysis_window->set_session(_session);
1877 analysis_window->show_all();
1880 analysis_window->set_rangemode();
1881 analysis_window->analyze();
1883 analysis_window->present();
1887 Editor::build_track_selection_context_menu ()
1889 using namespace Menu_Helpers;
1890 MenuList& edit_items = track_selection_context_menu.items();
1891 edit_items.clear ();
1893 add_selection_context_items (edit_items);
1894 // edit_items.push_back (SeparatorElem());
1895 // add_dstream_context_items (edit_items);
1897 return &track_selection_context_menu;
1901 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1903 using namespace Menu_Helpers;
1905 /* OK, stick the region submenu at the top of the list, and then add
1909 RegionSelection rs = get_regions_from_selection_and_entered ();
1911 string::size_type pos = 0;
1912 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1914 /* we have to hack up the region name because "_" has a special
1915 meaning for menu titles.
1918 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1919 menu_item_name.replace (pos, 1, "__");
1923 if (_popup_region_menu_item == 0) {
1924 _popup_region_menu_item = new MenuItem (menu_item_name);
1925 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1926 _popup_region_menu_item->show ();
1928 _popup_region_menu_item->set_label (menu_item_name);
1931 /* No latering allowed in later is higher layering model */
1932 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1933 if (act && Config->get_layer_model() == LaterHigher) {
1934 act->set_sensitive (false);
1936 act->set_sensitive (true);
1939 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1941 edit_items.push_back (*_popup_region_menu_item);
1942 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1943 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1945 edit_items.push_back (SeparatorElem());
1948 /** Add context menu items relevant to selection ranges.
1949 * @param edit_items List to add the items to.
1952 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1954 using namespace Menu_Helpers;
1956 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1957 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1959 edit_items.push_back (SeparatorElem());
1960 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1962 edit_items.push_back (SeparatorElem());
1963 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1964 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1966 edit_items.push_back (SeparatorElem());
1968 edit_items.push_back (
1970 _("Move Range Start to Previous Region Boundary"),
1971 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1975 edit_items.push_back (
1977 _("Move Range Start to Next Region Boundary"),
1978 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1982 edit_items.push_back (
1984 _("Move Range End to Previous Region Boundary"),
1985 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1989 edit_items.push_back (
1991 _("Move Range End to Next Region Boundary"),
1992 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1996 edit_items.push_back (SeparatorElem());
1997 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1998 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
2000 edit_items.push_back (SeparatorElem());
2001 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
2003 edit_items.push_back (SeparatorElem());
2004 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
2005 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
2006 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
2008 edit_items.push_back (SeparatorElem());
2009 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
2011 edit_items.push_back (SeparatorElem());
2012 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
2013 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
2015 edit_items.push_back (SeparatorElem());
2016 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
2017 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
2018 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
2019 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
2020 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
2021 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
2022 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2028 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2030 using namespace Menu_Helpers;
2034 Menu *play_menu = manage (new Menu);
2035 MenuList& play_items = play_menu->items();
2036 play_menu->set_name ("ArdourContextMenu");
2038 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2039 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2040 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2041 play_items.push_back (SeparatorElem());
2042 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2044 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2048 Menu *select_menu = manage (new Menu);
2049 MenuList& select_items = select_menu->items();
2050 select_menu->set_name ("ArdourContextMenu");
2052 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2053 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2054 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2055 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2056 select_items.push_back (SeparatorElem());
2057 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2058 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2059 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2060 select_items.push_back (SeparatorElem());
2061 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2062 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2063 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2064 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2065 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2066 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2067 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2069 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2073 Menu *cutnpaste_menu = manage (new Menu);
2074 MenuList& cutnpaste_items = cutnpaste_menu->items();
2075 cutnpaste_menu->set_name ("ArdourContextMenu");
2077 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2078 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2079 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2081 cutnpaste_items.push_back (SeparatorElem());
2083 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2084 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2086 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2088 /* Adding new material */
2090 edit_items.push_back (SeparatorElem());
2091 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2092 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2096 Menu *nudge_menu = manage (new Menu());
2097 MenuList& nudge_items = nudge_menu->items();
2098 nudge_menu->set_name ("ArdourContextMenu");
2100 edit_items.push_back (SeparatorElem());
2101 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2102 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2103 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2104 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2106 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2110 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2112 using namespace Menu_Helpers;
2116 Menu *play_menu = manage (new Menu);
2117 MenuList& play_items = play_menu->items();
2118 play_menu->set_name ("ArdourContextMenu");
2120 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2121 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2122 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2126 Menu *select_menu = manage (new Menu);
2127 MenuList& select_items = select_menu->items();
2128 select_menu->set_name ("ArdourContextMenu");
2130 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2131 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2132 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2133 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2134 select_items.push_back (SeparatorElem());
2135 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2136 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2137 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2138 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2140 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2144 Menu *cutnpaste_menu = manage (new Menu);
2145 MenuList& cutnpaste_items = cutnpaste_menu->items();
2146 cutnpaste_menu->set_name ("ArdourContextMenu");
2148 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2149 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2150 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2152 Menu *nudge_menu = manage (new Menu());
2153 MenuList& nudge_items = nudge_menu->items();
2154 nudge_menu->set_name ("ArdourContextMenu");
2156 edit_items.push_back (SeparatorElem());
2157 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2158 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2159 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2160 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2162 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2166 Editor::snap_type() const
2172 Editor::snap_musical() const
2174 switch (_snap_type) {
2175 case SnapToBeatDiv128:
2176 case SnapToBeatDiv64:
2177 case SnapToBeatDiv32:
2178 case SnapToBeatDiv28:
2179 case SnapToBeatDiv24:
2180 case SnapToBeatDiv20:
2181 case SnapToBeatDiv16:
2182 case SnapToBeatDiv14:
2183 case SnapToBeatDiv12:
2184 case SnapToBeatDiv10:
2185 case SnapToBeatDiv8:
2186 case SnapToBeatDiv7:
2187 case SnapToBeatDiv6:
2188 case SnapToBeatDiv5:
2189 case SnapToBeatDiv4:
2190 case SnapToBeatDiv3:
2191 case SnapToBeatDiv2:
2203 Editor::snap_mode() const
2209 Editor::set_snap_to (SnapType st)
2211 unsigned int snap_ind = (unsigned int)st;
2213 if (internal_editing()) {
2214 internal_snap_type = st;
2216 pre_internal_snap_type = st;
2221 if (snap_ind > snap_type_strings.size() - 1) {
2223 _snap_type = (SnapType)snap_ind;
2226 string str = snap_type_strings[snap_ind];
2228 if (str != snap_type_selector.get_text()) {
2229 snap_type_selector.set_text (str);
2234 switch (_snap_type) {
2235 case SnapToBeatDiv128:
2236 case SnapToBeatDiv64:
2237 case SnapToBeatDiv32:
2238 case SnapToBeatDiv28:
2239 case SnapToBeatDiv24:
2240 case SnapToBeatDiv20:
2241 case SnapToBeatDiv16:
2242 case SnapToBeatDiv14:
2243 case SnapToBeatDiv12:
2244 case SnapToBeatDiv10:
2245 case SnapToBeatDiv8:
2246 case SnapToBeatDiv7:
2247 case SnapToBeatDiv6:
2248 case SnapToBeatDiv5:
2249 case SnapToBeatDiv4:
2250 case SnapToBeatDiv3:
2251 case SnapToBeatDiv2: {
2252 std::vector<TempoMap::BBTPoint> grid;
2253 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
2254 compute_bbt_ruler_scale (grid, leftmost_frame, leftmost_frame + current_page_samples());
2255 update_tempo_based_rulers (grid);
2259 case SnapToRegionStart:
2260 case SnapToRegionEnd:
2261 case SnapToRegionSync:
2262 case SnapToRegionBoundary:
2263 build_region_boundary_cache ();
2271 redisplay_tempo (false);
2273 SnapChanged (); /* EMIT SIGNAL */
2277 Editor::set_snap_mode (SnapMode mode)
2279 string str = snap_mode_strings[(int)mode];
2281 if (internal_editing()) {
2282 internal_snap_mode = mode;
2284 pre_internal_snap_mode = mode;
2289 if (str != snap_mode_selector.get_text ()) {
2290 snap_mode_selector.set_text (str);
2297 Editor::set_edit_point_preference (EditPoint ep, bool force)
2299 bool changed = (_edit_point != ep);
2302 if (Profile->get_mixbus())
2303 if (ep == EditAtSelectedMarker)
2304 ep = EditAtPlayhead;
2306 string str = edit_point_strings[(int)ep];
2307 if (str != edit_point_selector.get_text ()) {
2308 edit_point_selector.set_text (str);
2311 update_all_enter_cursors();
2313 if (!force && !changed) {
2317 const char* action=NULL;
2319 switch (_edit_point) {
2320 case EditAtPlayhead:
2321 action = "edit-at-playhead";
2323 case EditAtSelectedMarker:
2324 action = "edit-at-marker";
2327 action = "edit-at-mouse";
2331 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2333 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2337 bool in_track_canvas;
2339 if (!mouse_frame (foo, in_track_canvas)) {
2340 in_track_canvas = false;
2343 reset_canvas_action_sensitivity (in_track_canvas);
2349 Editor::set_state (const XMLNode& node, int version)
2351 XMLProperty const * prop;
2353 PBD::Unwinder<bool> nsi (no_save_instant, true);
2356 Tabbable::set_state (node, version);
2358 if (_session && (prop = node.property ("playhead"))) {
2360 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2362 playhead_cursor->set_position (pos);
2364 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2365 playhead_cursor->set_position (0);
2368 playhead_cursor->set_position (0);
2371 if ((prop = node.property ("mixer-width"))) {
2372 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2375 if ((prop = node.property ("zoom-focus"))) {
2376 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2379 if ((prop = node.property ("zoom"))) {
2380 /* older versions of ardour used floating point samples_per_pixel */
2381 double f = PBD::atof (prop->value());
2382 reset_zoom (llrintf (f));
2384 reset_zoom (samples_per_pixel);
2387 if ((prop = node.property ("visible-track-count"))) {
2388 set_visible_track_count (PBD::atoi (prop->value()));
2391 if ((prop = node.property ("snap-to"))) {
2392 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2393 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2396 if ((prop = node.property ("snap-mode"))) {
2397 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2398 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2399 * snap_mode_selection_done() will only mark an already active item as active
2400 * which does not trigger set_text().
2402 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2405 if ((prop = node.property ("internal-snap-to"))) {
2406 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2409 if ((prop = node.property ("internal-snap-mode"))) {
2410 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2413 if ((prop = node.property ("pre-internal-snap-to"))) {
2414 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2417 if ((prop = node.property ("pre-internal-snap-mode"))) {
2418 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2421 if ((prop = node.property ("mouse-mode"))) {
2422 MouseMode m = str2mousemode(prop->value());
2423 set_mouse_mode (m, true);
2425 set_mouse_mode (MouseObject, true);
2428 if ((prop = node.property ("left-frame")) != 0) {
2430 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2434 reset_x_origin (pos);
2438 if ((prop = node.property ("y-origin")) != 0) {
2439 reset_y_origin (atof (prop->value ()));
2442 if ((prop = node.property ("join-object-range"))) {
2443 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2444 bool yn = string_is_affirmative (prop->value());
2446 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2447 tact->set_active (!yn);
2448 tact->set_active (yn);
2450 set_mouse_mode(mouse_mode, true);
2453 if ((prop = node.property ("edit-point"))) {
2454 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2457 if ((prop = node.property ("show-measures"))) {
2458 bool yn = string_is_affirmative (prop->value());
2459 _show_measures = yn;
2462 if ((prop = node.property ("follow-playhead"))) {
2463 bool yn = string_is_affirmative (prop->value());
2464 set_follow_playhead (yn);
2467 if ((prop = node.property ("stationary-playhead"))) {
2468 bool yn = string_is_affirmative (prop->value());
2469 set_stationary_playhead (yn);
2472 if ((prop = node.property ("region-list-sort-type"))) {
2473 RegionListSortType st;
2474 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2477 if ((prop = node.property ("show-editor-mixer"))) {
2479 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2482 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2483 bool yn = string_is_affirmative (prop->value());
2485 /* do it twice to force the change */
2487 tact->set_active (!yn);
2488 tact->set_active (yn);
2491 if ((prop = node.property ("show-editor-list"))) {
2493 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2496 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2497 bool yn = string_is_affirmative (prop->value());
2499 /* do it twice to force the change */
2501 tact->set_active (!yn);
2502 tact->set_active (yn);
2505 if ((prop = node.property (X_("editor-list-page")))) {
2506 _the_notebook.set_current_page (atoi (prop->value ()));
2509 if ((prop = node.property (X_("show-marker-lines")))) {
2510 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2512 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2513 bool yn = string_is_affirmative (prop->value ());
2515 tact->set_active (!yn);
2516 tact->set_active (yn);
2519 XMLNodeList children = node.children ();
2520 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2521 selection->set_state (**i, Stateful::current_state_version);
2522 _regions->set_state (**i);
2525 if ((prop = node.property ("maximised"))) {
2526 bool yn = string_is_affirmative (prop->value());
2527 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2529 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2530 bool fs = tact && tact->get_active();
2532 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2536 if ((prop = node.property ("nudge-clock-value"))) {
2538 sscanf (prop->value().c_str(), "%" PRId64, &f);
2539 nudge_clock->set (f);
2541 nudge_clock->set_mode (AudioClock::Timecode);
2542 nudge_clock->set (_session->frame_rate() * 5, true);
2547 * Not all properties may have been in XML, but
2548 * those that are linked to a private variable may need changing
2553 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2555 yn = _show_measures;
2556 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2557 /* do it twice to force the change */
2558 tact->set_active (!yn);
2559 tact->set_active (yn);
2562 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2563 yn = _follow_playhead;
2565 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2566 if (tact->get_active() != yn) {
2567 tact->set_active (yn);
2571 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2572 yn = _stationary_playhead;
2574 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2575 if (tact->get_active() != yn) {
2576 tact->set_active (yn);
2581 return LuaInstance::instance()->set_state(node);
2585 Editor::get_state ()
2587 XMLNode* node = new XMLNode (X_("Editor"));
2591 id().print (buf, sizeof (buf));
2592 node->add_property ("id", buf);
2594 node->add_child_nocopy (Tabbable::get_state());
2596 snprintf(buf,sizeof(buf), "%f", edit_pane.get_divider ());
2597 node->add_property("edit-horizontal-pane-pos", string(buf));
2598 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2599 snprintf(buf,sizeof(buf), "%f", editor_summary_pane.get_divider());
2600 node->add_property("edit-vertical-pane-pos", string(buf));
2602 maybe_add_mixer_strip_width (*node);
2604 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2606 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2607 node->add_property ("zoom", buf);
2608 node->add_property ("snap-to", enum_2_string (_snap_type));
2609 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2610 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2611 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2612 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2613 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2614 node->add_property ("edit-point", enum_2_string (_edit_point));
2615 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2616 node->add_property ("visible-track-count", buf);
2618 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2619 node->add_property ("playhead", buf);
2620 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2621 node->add_property ("left-frame", buf);
2622 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2623 node->add_property ("y-origin", buf);
2625 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2626 node->add_property ("maximised", _maximised ? "yes" : "no");
2627 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2628 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2629 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2630 node->add_property ("mouse-mode", enum2str(mouse_mode));
2631 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2633 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2635 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2636 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2639 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2641 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2642 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2645 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2646 node->add_property (X_("editor-list-page"), buf);
2648 if (button_bindings) {
2649 XMLNode* bb = new XMLNode (X_("Buttons"));
2650 button_bindings->save (*bb);
2651 node->add_child_nocopy (*bb);
2654 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2656 node->add_child_nocopy (selection->get_state ());
2657 node->add_child_nocopy (_regions->get_state ());
2659 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2660 node->add_property ("nudge-clock-value", buf);
2662 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2663 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2668 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2669 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2671 * @return pair: TimeAxisView that y is over, layer index.
2673 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2674 * in stacked or expanded region display mode, otherwise 0.
2676 std::pair<TimeAxisView *, double>
2677 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2679 if (!trackview_relative_offset) {
2680 y -= _trackview_group->canvas_origin().y;
2684 return std::make_pair ( (TimeAxisView *) 0, 0);
2687 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2689 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2696 return std::make_pair ( (TimeAxisView *) 0, 0);
2699 /** Snap a position to the grid, if appropriate, taking into account current
2700 * grid settings and also the state of any snap modifier keys that may be pressed.
2701 * @param start Position to snap.
2702 * @param event Event to get current key modifier information from, or 0.
2705 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2707 if (!_session || !event) {
2711 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2712 if (_snap_mode == SnapOff) {
2713 snap_to_internal (start, direction, for_mark);
2716 if (_snap_mode != SnapOff) {
2717 snap_to_internal (start, direction, for_mark);
2718 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2719 /* SnapOff, but we pressed the snap_delta modifier */
2720 snap_to_internal (start, direction, for_mark);
2726 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2728 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2732 snap_to_internal (start, direction, for_mark, ensure_snap);
2736 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2738 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2739 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2741 switch (_snap_type) {
2742 case SnapToTimecodeFrame:
2743 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2744 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2745 /* start is already on a whole timecode frame, do nothing */
2746 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2747 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2749 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2753 case SnapToTimecodeSeconds:
2754 if (_session->config.get_timecode_offset_negative()) {
2755 start += _session->config.get_timecode_offset ();
2757 start -= _session->config.get_timecode_offset ();
2759 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2760 (start % one_timecode_second == 0)) {
2761 /* start is already on a whole second, do nothing */
2762 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2763 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2765 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2768 if (_session->config.get_timecode_offset_negative()) {
2769 start -= _session->config.get_timecode_offset ();
2771 start += _session->config.get_timecode_offset ();
2775 case SnapToTimecodeMinutes:
2776 if (_session->config.get_timecode_offset_negative()) {
2777 start += _session->config.get_timecode_offset ();
2779 start -= _session->config.get_timecode_offset ();
2781 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2782 (start % one_timecode_minute == 0)) {
2783 /* start is already on a whole minute, do nothing */
2784 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2785 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2787 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2789 if (_session->config.get_timecode_offset_negative()) {
2790 start -= _session->config.get_timecode_offset ();
2792 start += _session->config.get_timecode_offset ();
2796 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2797 abort(); /*NOTREACHED*/
2802 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2804 const framepos_t one_second = _session->frame_rate();
2805 const framepos_t one_minute = _session->frame_rate() * 60;
2806 framepos_t presnap = start;
2810 switch (_snap_type) {
2811 case SnapToTimecodeFrame:
2812 case SnapToTimecodeSeconds:
2813 case SnapToTimecodeMinutes:
2814 return timecode_snap_to_internal (start, direction, for_mark);
2817 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2818 start % (one_second/75) == 0) {
2819 /* start is already on a whole CD frame, do nothing */
2820 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2821 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2823 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2828 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2829 start % one_second == 0) {
2830 /* start is already on a whole second, do nothing */
2831 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2832 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2834 start = (framepos_t) floor ((double) start / one_second) * one_second;
2839 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2840 start % one_minute == 0) {
2841 /* start is already on a whole minute, do nothing */
2842 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2843 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2845 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2850 start = _session->tempo_map().round_to_bar (start, direction);
2854 start = _session->tempo_map().round_to_beat (start, direction);
2857 case SnapToBeatDiv128:
2858 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2860 case SnapToBeatDiv64:
2861 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2863 case SnapToBeatDiv32:
2864 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2866 case SnapToBeatDiv28:
2867 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2869 case SnapToBeatDiv24:
2870 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2872 case SnapToBeatDiv20:
2873 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2875 case SnapToBeatDiv16:
2876 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2878 case SnapToBeatDiv14:
2879 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2881 case SnapToBeatDiv12:
2882 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2884 case SnapToBeatDiv10:
2885 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2887 case SnapToBeatDiv8:
2888 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2890 case SnapToBeatDiv7:
2891 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2893 case SnapToBeatDiv6:
2894 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2896 case SnapToBeatDiv5:
2897 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2899 case SnapToBeatDiv4:
2900 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2902 case SnapToBeatDiv3:
2903 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2905 case SnapToBeatDiv2:
2906 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2914 _session->locations()->marks_either_side (start, before, after);
2916 if (before == max_framepos && after == max_framepos) {
2917 /* No marks to snap to, so just don't snap */
2919 } else if (before == max_framepos) {
2921 } else if (after == max_framepos) {
2923 } else if (before != max_framepos && after != max_framepos) {
2924 /* have before and after */
2925 if ((start - before) < (after - start)) {
2934 case SnapToRegionStart:
2935 case SnapToRegionEnd:
2936 case SnapToRegionSync:
2937 case SnapToRegionBoundary:
2938 if (!region_boundary_cache.empty()) {
2940 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2941 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2943 if (direction > 0) {
2944 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2946 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2949 if (next != region_boundary_cache.begin ()) {
2954 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2955 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2957 if (start > (p + n) / 2) {
2966 switch (_snap_mode) {
2976 if (presnap > start) {
2977 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2981 } else if (presnap < start) {
2982 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2988 /* handled at entry */
2996 Editor::setup_toolbar ()
2998 HBox* mode_box = manage(new HBox);
2999 mode_box->set_border_width (2);
3000 mode_box->set_spacing(2);
3002 HBox* mouse_mode_box = manage (new HBox);
3003 HBox* mouse_mode_hbox = manage (new HBox);
3004 VBox* mouse_mode_vbox = manage (new VBox);
3005 Alignment* mouse_mode_align = manage (new Alignment);
3007 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3008 mouse_mode_size_group->add_widget (smart_mode_button);
3009 mouse_mode_size_group->add_widget (mouse_move_button);
3010 mouse_mode_size_group->add_widget (mouse_cut_button);
3011 mouse_mode_size_group->add_widget (mouse_select_button);
3012 mouse_mode_size_group->add_widget (mouse_timefx_button);
3013 mouse_mode_size_group->add_widget (mouse_audition_button);
3014 mouse_mode_size_group->add_widget (mouse_draw_button);
3015 mouse_mode_size_group->add_widget (mouse_content_button);
3017 mouse_mode_size_group->add_widget (zoom_in_button);
3018 mouse_mode_size_group->add_widget (zoom_out_button);
3019 mouse_mode_size_group->add_widget (zoom_preset_selector);
3020 mouse_mode_size_group->add_widget (zoom_out_full_button);
3021 mouse_mode_size_group->add_widget (zoom_focus_selector);
3023 mouse_mode_size_group->add_widget (tav_shrink_button);
3024 mouse_mode_size_group->add_widget (tav_expand_button);
3025 mouse_mode_size_group->add_widget (visible_tracks_selector);
3027 mouse_mode_size_group->add_widget (snap_type_selector);
3028 mouse_mode_size_group->add_widget (snap_mode_selector);
3030 mouse_mode_size_group->add_widget (edit_point_selector);
3031 mouse_mode_size_group->add_widget (edit_mode_selector);
3033 mouse_mode_size_group->add_widget (*nudge_clock);
3034 mouse_mode_size_group->add_widget (nudge_forward_button);
3035 mouse_mode_size_group->add_widget (nudge_backward_button);
3037 mouse_mode_hbox->set_spacing (2);
3039 if (!ARDOUR::Profile->get_trx()) {
3040 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3043 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3044 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3046 if (!ARDOUR::Profile->get_mixbus()) {
3047 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3050 if (!ARDOUR::Profile->get_trx()) {
3051 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3052 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3053 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3054 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3057 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3059 mouse_mode_align->add (*mouse_mode_vbox);
3060 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3062 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3064 edit_mode_selector.set_name ("mouse mode button");
3066 if (!ARDOUR::Profile->get_trx()) {
3067 mode_box->pack_start (edit_mode_selector, false, false);
3070 mode_box->pack_start (*mouse_mode_box, false, false);
3074 _zoom_box.set_spacing (2);
3075 _zoom_box.set_border_width (2);
3079 zoom_preset_selector.set_name ("zoom button");
3080 zoom_preset_selector.set_image(::get_icon ("time_exp"));
3081 zoom_preset_selector.set_size_request (42, -1);
3083 zoom_in_button.set_name ("zoom button");
3084 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3085 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3086 zoom_in_button.set_related_action (act);
3088 zoom_out_button.set_name ("zoom button");
3089 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3090 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3091 zoom_out_button.set_related_action (act);
3093 zoom_out_full_button.set_name ("zoom button");
3094 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3095 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3096 zoom_out_full_button.set_related_action (act);
3098 zoom_focus_selector.set_name ("zoom button");
3100 if (ARDOUR::Profile->get_mixbus()) {
3101 _zoom_box.pack_start (zoom_preset_selector, false, false);
3102 } else if (ARDOUR::Profile->get_trx()) {
3103 mode_box->pack_start (zoom_out_button, false, false);
3104 mode_box->pack_start (zoom_in_button, false, false);
3106 _zoom_box.pack_start (zoom_out_button, false, false);
3107 _zoom_box.pack_start (zoom_in_button, false, false);
3108 _zoom_box.pack_start (zoom_out_full_button, false, false);
3109 _zoom_box.pack_start (zoom_focus_selector, false, false);
3112 /* Track zoom buttons */
3113 visible_tracks_selector.set_name ("zoom button");
3114 if (Profile->get_mixbus()) {
3115 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3116 visible_tracks_selector.set_size_request (42, -1);
3118 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3121 tav_expand_button.set_name ("zoom button");
3122 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3123 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3124 tav_expand_button.set_related_action (act);
3126 tav_shrink_button.set_name ("zoom button");
3127 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3128 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3129 tav_shrink_button.set_related_action (act);
3131 if (ARDOUR::Profile->get_mixbus()) {
3132 _zoom_box.pack_start (visible_tracks_selector);
3133 } else if (ARDOUR::Profile->get_trx()) {
3134 _zoom_box.pack_start (tav_shrink_button);
3135 _zoom_box.pack_start (tav_expand_button);
3137 _zoom_box.pack_start (visible_tracks_selector);
3138 _zoom_box.pack_start (tav_shrink_button);
3139 _zoom_box.pack_start (tav_expand_button);
3142 snap_box.set_spacing (2);
3143 snap_box.set_border_width (2);
3145 snap_type_selector.set_name ("mouse mode button");
3147 snap_mode_selector.set_name ("mouse mode button");
3149 edit_point_selector.set_name ("mouse mode button");
3151 snap_box.pack_start (snap_mode_selector, false, false);
3152 snap_box.pack_start (snap_type_selector, false, false);
3153 snap_box.pack_start (edit_point_selector, false, false);
3157 HBox *nudge_box = manage (new HBox);
3158 nudge_box->set_spacing (2);
3159 nudge_box->set_border_width (2);
3161 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3162 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3164 nudge_box->pack_start (nudge_backward_button, false, false);
3165 nudge_box->pack_start (nudge_forward_button, false, false);
3166 nudge_box->pack_start (*nudge_clock, false, false);
3169 /* Pack everything in... */
3171 HBox* hbox = manage (new HBox);
3172 hbox->set_spacing(2);
3174 toolbar_hbox.set_spacing (2);
3175 toolbar_hbox.set_border_width (1);
3177 toolbar_hbox.pack_start (*mode_box, false, false);
3178 if (!ARDOUR::Profile->get_trx()) {
3179 toolbar_hbox.pack_start (_zoom_box, false, false);
3180 toolbar_hbox.pack_start (*hbox, false, false);
3183 if (!ARDOUR::Profile->get_trx()) {
3184 hbox->pack_start (snap_box, false, false);
3185 hbox->pack_start (*nudge_box, false, false);
3190 toolbar_base.set_name ("ToolBarBase");
3191 toolbar_base.add (toolbar_hbox);
3193 _toolbar_viewport.add (toolbar_base);
3194 /* stick to the required height but allow width to vary if there's not enough room */
3195 _toolbar_viewport.set_size_request (1, -1);
3197 toolbar_frame.set_shadow_type (SHADOW_OUT);
3198 toolbar_frame.set_name ("BaseFrame");
3199 toolbar_frame.add (_toolbar_viewport);
3203 Editor::build_edit_point_menu ()
3205 using namespace Menu_Helpers;
3207 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3208 if(!Profile->get_mixbus())
3209 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3210 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3212 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3216 Editor::build_edit_mode_menu ()
3218 using namespace Menu_Helpers;
3220 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3221 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3222 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3223 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3225 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3229 Editor::build_snap_mode_menu ()
3231 using namespace Menu_Helpers;
3233 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3234 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3235 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3237 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3241 Editor::build_snap_type_menu ()
3243 using namespace Menu_Helpers;
3245 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3246 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3247 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3248 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3249 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3250 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3251 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3252 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3253 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3254 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3255 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3256 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3257 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3258 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3259 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3260 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3261 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3262 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3263 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3264 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3265 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3266 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3267 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3268 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3269 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3270 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3271 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3272 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3273 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3274 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3276 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3281 Editor::setup_tooltips ()
3283 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3284 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3285 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3286 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3287 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3288 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3289 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3290 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3291 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3292 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3293 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3294 set_tooltip (zoom_in_button, _("Zoom In"));
3295 set_tooltip (zoom_out_button, _("Zoom Out"));
3296 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3297 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3298 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3299 set_tooltip (tav_expand_button, _("Expand Tracks"));
3300 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3301 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3302 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3303 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3304 set_tooltip (edit_point_selector, _("Edit Point"));
3305 set_tooltip (edit_mode_selector, _("Edit Mode"));
3306 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3310 Editor::convert_drop_to_paths (
3311 vector<string>& paths,
3312 const RefPtr<Gdk::DragContext>& /*context*/,
3315 const SelectionData& data,
3319 if (_session == 0) {
3323 vector<string> uris = data.get_uris();
3327 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3328 are actually URI lists. So do it by hand.
3331 if (data.get_target() != "text/plain") {
3335 /* Parse the "uri-list" format that Nautilus provides,
3336 where each pathname is delimited by \r\n.
3338 THERE MAY BE NO NULL TERMINATING CHAR!!!
3341 string txt = data.get_text();
3345 p = (char *) malloc (txt.length() + 1);
3346 txt.copy (p, txt.length(), 0);
3347 p[txt.length()] = '\0';
3353 while (g_ascii_isspace (*p))
3357 while (*q && (*q != '\n') && (*q != '\r')) {
3364 while (q > p && g_ascii_isspace (*q))
3369 uris.push_back (string (p, q - p + 1));
3373 p = strchr (p, '\n');
3385 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3386 if ((*i).substr (0,7) == "file://") {
3387 paths.push_back (Glib::filename_from_uri (*i));
3395 Editor::new_tempo_section ()
3400 Editor::map_transport_state ()
3402 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3404 if (_session && _session->transport_stopped()) {
3405 have_pending_keyboard_selection = false;
3408 update_loop_range_view ();
3414 Editor::begin_selection_op_history ()
3416 selection_op_cmd_depth = 0;
3417 selection_op_history_it = 0;
3419 while(!selection_op_history.empty()) {
3420 delete selection_op_history.front();
3421 selection_op_history.pop_front();
3424 selection_undo_action->set_sensitive (false);
3425 selection_redo_action->set_sensitive (false);
3426 selection_op_history.push_front (&_selection_memento->get_state ());
3430 Editor::begin_reversible_selection_op (string name)
3433 //cerr << name << endl;
3434 /* begin/commit pairs can be nested */
3435 selection_op_cmd_depth++;
3440 Editor::commit_reversible_selection_op ()
3443 if (selection_op_cmd_depth == 1) {
3445 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3447 The user has undone some selection ops and then made a new one,
3448 making anything earlier in the list invalid.
3451 list<XMLNode *>::iterator it = selection_op_history.begin();
3452 list<XMLNode *>::iterator e_it = it;
3453 advance (e_it, selection_op_history_it);
3455 for ( ; it != e_it; ++it) {
3458 selection_op_history.erase (selection_op_history.begin(), e_it);
3461 selection_op_history.push_front (&_selection_memento->get_state ());
3462 selection_op_history_it = 0;
3464 selection_undo_action->set_sensitive (true);
3465 selection_redo_action->set_sensitive (false);
3468 if (selection_op_cmd_depth > 0) {
3469 selection_op_cmd_depth--;
3475 Editor::undo_selection_op ()
3478 selection_op_history_it++;
3480 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3481 if (n == selection_op_history_it) {
3482 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3483 selection_redo_action->set_sensitive (true);
3487 /* is there an earlier entry? */
3488 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3489 selection_undo_action->set_sensitive (false);
3495 Editor::redo_selection_op ()
3498 if (selection_op_history_it > 0) {
3499 selection_op_history_it--;
3502 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3503 if (n == selection_op_history_it) {
3504 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3505 selection_undo_action->set_sensitive (true);
3510 if (selection_op_history_it == 0) {
3511 selection_redo_action->set_sensitive (false);
3517 Editor::begin_reversible_command (string name)
3520 before.push_back (&_selection_memento->get_state ());
3521 _session->begin_reversible_command (name);
3526 Editor::begin_reversible_command (GQuark q)
3529 before.push_back (&_selection_memento->get_state ());
3530 _session->begin_reversible_command (q);
3535 Editor::abort_reversible_command ()
3538 while(!before.empty()) {
3539 delete before.front();
3542 _session->abort_reversible_command ();
3547 Editor::commit_reversible_command ()
3550 if (before.size() == 1) {
3551 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3552 redo_action->set_sensitive(false);
3553 undo_action->set_sensitive(true);
3554 begin_selection_op_history ();
3557 if (before.empty()) {
3558 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3563 _session->commit_reversible_command ();
3568 Editor::history_changed ()
3572 if (undo_action && _session) {
3573 if (_session->undo_depth() == 0) {
3574 label = S_("Command|Undo");
3576 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3578 undo_action->property_label() = label;
3581 if (redo_action && _session) {
3582 if (_session->redo_depth() == 0) {
3584 redo_action->set_sensitive (false);
3586 label = string_compose(_("Redo (%1)"), _session->next_redo());
3587 redo_action->set_sensitive (true);
3589 redo_action->property_label() = label;
3594 Editor::duplicate_range (bool with_dialog)
3598 RegionSelection rs = get_regions_from_selection_and_entered ();
3600 if ( selection->time.length() == 0 && rs.empty()) {
3606 ArdourDialog win (_("Duplicate"));
3607 Label label (_("Number of duplications:"));
3608 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3609 SpinButton spinner (adjustment, 0.0, 1);
3612 win.get_vbox()->set_spacing (12);
3613 win.get_vbox()->pack_start (hbox);
3614 hbox.set_border_width (6);
3615 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3617 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3618 place, visually. so do this by hand.
3621 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3622 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3623 spinner.grab_focus();
3629 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3630 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3631 win.set_default_response (RESPONSE_ACCEPT);
3633 spinner.grab_focus ();
3635 switch (win.run ()) {
3636 case RESPONSE_ACCEPT:
3642 times = adjustment.get_value();
3645 if ((current_mouse_mode() == Editing::MouseRange)) {
3646 if (selection->time.length()) {
3647 duplicate_selection (times);
3649 } else if (get_smart_mode()) {
3650 if (selection->time.length()) {
3651 duplicate_selection (times);
3653 duplicate_some_regions (rs, times);
3655 duplicate_some_regions (rs, times);
3660 Editor::set_edit_mode (EditMode m)
3662 Config->set_edit_mode (m);
3666 Editor::cycle_edit_mode ()
3668 switch (Config->get_edit_mode()) {
3670 Config->set_edit_mode (Ripple);
3674 Config->set_edit_mode (Lock);
3677 Config->set_edit_mode (Slide);
3683 Editor::edit_mode_selection_done ( EditMode m )
3685 Config->set_edit_mode ( m );
3689 Editor::snap_type_selection_done (SnapType snaptype)
3691 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3693 ract->set_active ();
3698 Editor::snap_mode_selection_done (SnapMode mode)
3700 RefPtr<RadioAction> ract = snap_mode_action (mode);
3703 ract->set_active (true);
3708 Editor::cycle_edit_point (bool with_marker)
3710 if(Profile->get_mixbus())
3711 with_marker = false;
3713 switch (_edit_point) {
3715 set_edit_point_preference (EditAtPlayhead);
3717 case EditAtPlayhead:
3719 set_edit_point_preference (EditAtSelectedMarker);
3721 set_edit_point_preference (EditAtMouse);
3724 case EditAtSelectedMarker:
3725 set_edit_point_preference (EditAtMouse);
3731 Editor::edit_point_selection_done (EditPoint ep)
3733 set_edit_point_preference ( ep );
3737 Editor::build_zoom_focus_menu ()
3739 using namespace Menu_Helpers;
3741 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3742 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3743 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3744 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3745 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3746 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3748 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3752 Editor::zoom_focus_selection_done ( ZoomFocus f )
3754 RefPtr<RadioAction> ract = zoom_focus_action (f);
3756 ract->set_active ();
3761 Editor::build_track_count_menu ()
3763 using namespace Menu_Helpers;
3765 if (!Profile->get_mixbus()) {
3766 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3767 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3768 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3769 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3770 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3771 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3772 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3773 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3774 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3775 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3776 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3777 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3778 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3780 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3781 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3782 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3783 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3784 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3785 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3786 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3787 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3788 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3789 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3791 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3792 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3793 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3794 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3795 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3796 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3797 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3798 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3799 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3800 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3801 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3806 Editor::set_zoom_preset (int64_t ms)
3809 temporal_zoom_session();
3813 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3814 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3818 Editor::set_visible_track_count (int32_t n)
3820 _visible_track_count = n;
3822 /* if the canvas hasn't really been allocated any size yet, just
3823 record the desired number of visible tracks and return. when canvas
3824 allocation happens, we will get called again and then we can do the
3828 if (_visible_canvas_height <= 1) {
3834 DisplaySuspender ds;
3836 if (_visible_track_count > 0) {
3837 h = trackviews_height() / _visible_track_count;
3838 std::ostringstream s;
3839 s << _visible_track_count;
3841 } else if (_visible_track_count == 0) {
3843 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3844 if ((*i)->marked_for_display()) {
3848 h = trackviews_height() / n;
3851 /* negative value means that the visible track count has
3852 been overridden by explicit track height changes.
3854 visible_tracks_selector.set_text (X_("*"));
3858 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3859 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3862 if (str != visible_tracks_selector.get_text()) {
3863 visible_tracks_selector.set_text (str);
3868 Editor::override_visible_track_count ()
3870 _visible_track_count = -1;
3871 visible_tracks_selector.set_text ( _("*") );
3875 Editor::edit_controls_button_release (GdkEventButton* ev)
3877 if (Keyboard::is_context_menu_event (ev)) {
3878 ARDOUR_UI::instance()->add_route ();
3879 } else if (ev->button == 1) {
3880 selection->clear_tracks ();
3887 Editor::mouse_select_button_release (GdkEventButton* ev)
3889 /* this handles just right-clicks */
3891 if (ev->button != 3) {
3899 Editor::set_zoom_focus (ZoomFocus f)
3901 string str = zoom_focus_strings[(int)f];
3903 if (str != zoom_focus_selector.get_text()) {
3904 zoom_focus_selector.set_text (str);
3907 if (zoom_focus != f) {
3914 Editor::cycle_zoom_focus ()
3916 switch (zoom_focus) {
3918 set_zoom_focus (ZoomFocusRight);
3920 case ZoomFocusRight:
3921 set_zoom_focus (ZoomFocusCenter);
3923 case ZoomFocusCenter:
3924 set_zoom_focus (ZoomFocusPlayhead);
3926 case ZoomFocusPlayhead:
3927 set_zoom_focus (ZoomFocusMouse);
3929 case ZoomFocusMouse:
3930 set_zoom_focus (ZoomFocusEdit);
3933 set_zoom_focus (ZoomFocusLeft);
3939 Editor::set_show_measures (bool yn)
3941 if (_show_measures != yn) {
3944 if ((_show_measures = yn) == true) {
3946 tempo_lines->show();
3949 std::vector<TempoMap::BBTPoint> grid;
3950 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3951 draw_measures (grid);
3959 Editor::toggle_follow_playhead ()
3961 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3963 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3964 set_follow_playhead (tact->get_active());
3968 /** @param yn true to follow playhead, otherwise false.
3969 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3972 Editor::set_follow_playhead (bool yn, bool catch_up)
3974 if (_follow_playhead != yn) {
3975 if ((_follow_playhead = yn) == true && catch_up) {
3977 reset_x_origin_to_follow_playhead ();
3984 Editor::toggle_stationary_playhead ()
3986 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3988 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3989 set_stationary_playhead (tact->get_active());
3994 Editor::set_stationary_playhead (bool yn)
3996 if (_stationary_playhead != yn) {
3997 if ((_stationary_playhead = yn) == true) {
3999 // FIXME need a 3.0 equivalent of this 2.X call
4000 // update_current_screen ();
4007 Editor::playlist_selector () const
4009 return *_playlist_selector;
4013 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4015 if (paste_count == 0) {
4016 /* don't bother calculating an offset that will be zero anyway */
4020 /* calculate basic unsnapped multi-paste offset */
4021 framecnt_t offset = paste_count * duration;
4023 /* snap offset so pos + offset is aligned to the grid */
4024 framepos_t offset_pos = pos + offset;
4025 snap_to(offset_pos, RoundUpMaybe);
4026 offset = offset_pos - pos;
4032 Editor::get_grid_beat_divisions(framepos_t position)
4034 switch (_snap_type) {
4035 case SnapToBeatDiv128: return 128;
4036 case SnapToBeatDiv64: return 64;
4037 case SnapToBeatDiv32: return 32;
4038 case SnapToBeatDiv28: return 28;
4039 case SnapToBeatDiv24: return 24;
4040 case SnapToBeatDiv20: return 20;
4041 case SnapToBeatDiv16: return 16;
4042 case SnapToBeatDiv14: return 14;
4043 case SnapToBeatDiv12: return 12;
4044 case SnapToBeatDiv10: return 10;
4045 case SnapToBeatDiv8: return 8;
4046 case SnapToBeatDiv7: return 7;
4047 case SnapToBeatDiv6: return 6;
4048 case SnapToBeatDiv5: return 5;
4049 case SnapToBeatDiv4: return 4;
4050 case SnapToBeatDiv3: return 3;
4051 case SnapToBeatDiv2: return 2;
4058 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4062 const unsigned divisions = get_grid_beat_divisions(position);
4064 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4067 switch (_snap_type) {
4069 return Evoral::Beats(1.0);
4072 return Evoral::Beats(_session->tempo_map().meter_at_frame (position).divisions_per_bar());
4080 return Evoral::Beats();
4084 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4088 ret = nudge_clock->current_duration (pos);
4089 next = ret + 1; /* XXXX fix me */
4095 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4097 ArdourDialog dialog (_("Playlist Deletion"));
4098 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4099 "If it is kept, its audio files will not be cleaned.\n"
4100 "If it is deleted, audio files used by it alone will be cleaned."),
4103 dialog.set_position (WIN_POS_CENTER);
4104 dialog.get_vbox()->pack_start (label);
4108 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4109 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4110 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4111 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4112 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4114 // by default gtk uses the left most button
4115 keep->grab_focus ();
4117 switch (dialog.run ()) {
4119 /* keep this and all remaining ones */
4124 /* delete this and all others */
4128 case RESPONSE_ACCEPT:
4129 /* delete the playlist */
4133 case RESPONSE_REJECT:
4134 /* keep the playlist */
4146 Editor::audio_region_selection_covers (framepos_t where)
4148 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4149 if ((*a)->region()->covers (where)) {
4158 Editor::prepare_for_cleanup ()
4160 cut_buffer->clear_regions ();
4161 cut_buffer->clear_playlists ();
4163 selection->clear_regions ();
4164 selection->clear_playlists ();
4166 _regions->suspend_redisplay ();
4170 Editor::finish_cleanup ()
4172 _regions->resume_redisplay ();
4176 Editor::transport_loop_location()
4179 return _session->locations()->auto_loop_location();
4186 Editor::transport_punch_location()
4189 return _session->locations()->auto_punch_location();
4196 Editor::control_layout_scroll (GdkEventScroll* ev)
4198 /* Just forward to the normal canvas scroll method. The coordinate
4199 systems are different but since the canvas is always larger than the
4200 track headers, and aligned with the trackview area, this will work.
4202 In the not too distant future this layout is going away anyway and
4203 headers will be on the canvas.
4205 return canvas_scroll_event (ev, false);
4209 Editor::session_state_saved (string)
4212 _snapshots->redisplay ();
4216 Editor::maximise_editing_space ()
4222 Gtk::Window* toplevel = current_toplevel();
4225 toplevel->fullscreen ();
4231 Editor::restore_editing_space ()
4237 Gtk::Window* toplevel = current_toplevel();
4240 toplevel->unfullscreen();
4246 * Make new playlists for a given track and also any others that belong
4247 * to the same active route group with the `select' property.
4252 Editor::new_playlists (TimeAxisView* v)
4254 begin_reversible_command (_("new playlists"));
4255 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4256 _session->playlists->get (playlists);
4257 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4258 commit_reversible_command ();
4262 * Use a copy of the current playlist for a given track and also any others that belong
4263 * to the same active route group with the `select' property.
4268 Editor::copy_playlists (TimeAxisView* v)
4270 begin_reversible_command (_("copy playlists"));
4271 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4272 _session->playlists->get (playlists);
4273 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4274 commit_reversible_command ();
4277 /** Clear the current playlist for a given track and also any others that belong
4278 * to the same active route group with the `select' property.
4283 Editor::clear_playlists (TimeAxisView* v)
4285 begin_reversible_command (_("clear playlists"));
4286 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4287 _session->playlists->get (playlists);
4288 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4289 commit_reversible_command ();
4293 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4295 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4299 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4301 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4305 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4307 atv.clear_playlist ();
4311 Editor::get_y_origin () const
4313 return vertical_adjustment.get_value ();
4316 /** Queue up a change to the viewport x origin.
4317 * @param frame New x origin.
4320 Editor::reset_x_origin (framepos_t frame)
4322 pending_visual_change.add (VisualChange::TimeOrigin);
4323 pending_visual_change.time_origin = frame;
4324 ensure_visual_change_idle_handler ();
4328 Editor::reset_y_origin (double y)
4330 pending_visual_change.add (VisualChange::YOrigin);
4331 pending_visual_change.y_origin = y;
4332 ensure_visual_change_idle_handler ();
4336 Editor::reset_zoom (framecnt_t spp)
4338 if (spp == samples_per_pixel) {
4342 pending_visual_change.add (VisualChange::ZoomLevel);
4343 pending_visual_change.samples_per_pixel = spp;
4344 ensure_visual_change_idle_handler ();
4348 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4350 reset_x_origin (frame);
4353 if (!no_save_visual) {
4354 undo_visual_stack.push_back (current_visual_state(false));
4358 Editor::VisualState::VisualState (bool with_tracks)
4359 : gui_state (with_tracks ? new GUIObjectState : 0)
4363 Editor::VisualState::~VisualState ()
4368 Editor::VisualState*
4369 Editor::current_visual_state (bool with_tracks)
4371 VisualState* vs = new VisualState (with_tracks);
4372 vs->y_position = vertical_adjustment.get_value();
4373 vs->samples_per_pixel = samples_per_pixel;
4374 vs->leftmost_frame = leftmost_frame;
4375 vs->zoom_focus = zoom_focus;
4378 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4385 Editor::undo_visual_state ()
4387 if (undo_visual_stack.empty()) {
4391 VisualState* vs = undo_visual_stack.back();
4392 undo_visual_stack.pop_back();
4395 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4398 use_visual_state (*vs);
4403 Editor::redo_visual_state ()
4405 if (redo_visual_stack.empty()) {
4409 VisualState* vs = redo_visual_stack.back();
4410 redo_visual_stack.pop_back();
4412 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4413 // why do we check here?
4414 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4417 use_visual_state (*vs);
4422 Editor::swap_visual_state ()
4424 if (undo_visual_stack.empty()) {
4425 redo_visual_state ();
4427 undo_visual_state ();
4432 Editor::use_visual_state (VisualState& vs)
4434 PBD::Unwinder<bool> nsv (no_save_visual, true);
4435 DisplaySuspender ds;
4437 vertical_adjustment.set_value (vs.y_position);
4439 set_zoom_focus (vs.zoom_focus);
4440 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4443 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4445 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4446 (*i)->clear_property_cache();
4447 (*i)->reset_visual_state ();
4451 _routes->update_visibility ();
4454 /** This is the core function that controls the zoom level of the canvas. It is called
4455 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4456 * @param spp new number of samples per pixel
4459 Editor::set_samples_per_pixel (framecnt_t spp)
4465 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4466 const framecnt_t lots_of_pixels = 4000;
4468 /* if the zoom level is greater than what you'd get trying to display 3
4469 * days of audio on a really big screen, then it's too big.
4472 if (spp * lots_of_pixels > three_days) {
4476 samples_per_pixel = spp;
4479 tempo_lines->tempo_map_changed();
4482 bool const showing_time_selection = selection->time.length() > 0;
4484 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4485 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4486 (*i)->reshow_selection (selection->time);
4490 ZoomChanged (); /* EMIT_SIGNAL */
4492 ArdourCanvas::GtkCanvasViewport* c;
4494 c = get_track_canvas();
4496 c->canvas()->zoomed ();
4499 if (playhead_cursor) {
4500 playhead_cursor->set_position (playhead_cursor->current_frame ());
4503 refresh_location_display();
4504 _summary->set_overlays_dirty ();
4506 update_marker_labels ();
4512 Editor::queue_visual_videotimeline_update ()
4515 * pending_visual_change.add (VisualChange::VideoTimeline);
4516 * or maybe even more specific: which videotimeline-image
4517 * currently it calls update_video_timeline() to update
4518 * _all outdated_ images on the video-timeline.
4519 * see 'exposeimg()' in video_image_frame.cc
4521 ensure_visual_change_idle_handler ();
4525 Editor::ensure_visual_change_idle_handler ()
4527 if (pending_visual_change.idle_handler_id < 0) {
4528 // see comment in add_to_idle_resize above.
4529 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4530 pending_visual_change.being_handled = false;
4535 Editor::_idle_visual_changer (void* arg)
4537 return static_cast<Editor*>(arg)->idle_visual_changer ();
4541 Editor::idle_visual_changer ()
4543 /* set_horizontal_position() below (and maybe other calls) call
4544 gtk_main_iteration(), so it's possible that a signal will be handled
4545 half-way through this method. If this signal wants an
4546 idle_visual_changer we must schedule another one after this one, so
4547 mark the idle_handler_id as -1 here to allow that. Also make a note
4548 that we are doing the visual change, so that changes in response to
4549 super-rapid-screen-update can be dropped if we are still processing
4553 pending_visual_change.idle_handler_id = -1;
4554 pending_visual_change.being_handled = true;
4556 VisualChange vc = pending_visual_change;
4558 pending_visual_change.pending = (VisualChange::Type) 0;
4560 visual_changer (vc);
4562 pending_visual_change.being_handled = false;
4564 return 0; /* this is always a one-shot call */
4568 Editor::visual_changer (const VisualChange& vc)
4570 double const last_time_origin = horizontal_position ();
4572 if (vc.pending & VisualChange::ZoomLevel) {
4573 set_samples_per_pixel (vc.samples_per_pixel);
4575 compute_fixed_ruler_scale ();
4577 std::vector<TempoMap::BBTPoint> grid;
4578 compute_current_bbt_points (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4579 compute_bbt_ruler_scale (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4580 update_tempo_based_rulers (grid);
4582 update_video_timeline();
4585 if (vc.pending & VisualChange::TimeOrigin) {
4586 set_horizontal_position (vc.time_origin / samples_per_pixel);
4589 if (vc.pending & VisualChange::YOrigin) {
4590 vertical_adjustment.set_value (vc.y_origin);
4593 if (last_time_origin == horizontal_position ()) {
4594 /* changed signal not emitted */
4595 update_fixed_rulers ();
4596 redisplay_tempo (true);
4599 if (!(vc.pending & VisualChange::ZoomLevel)) {
4600 update_video_timeline();
4603 _summary->set_overlays_dirty ();
4606 struct EditorOrderTimeAxisSorter {
4607 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4608 return a->order () < b->order ();
4613 Editor::sort_track_selection (TrackViewList& sel)
4615 EditorOrderTimeAxisSorter cmp;
4620 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4623 framepos_t where = 0;
4624 EditPoint ep = _edit_point;
4626 if (Profile->get_mixbus())
4627 if (ep == EditAtSelectedMarker)
4628 ep = EditAtPlayhead;
4630 if (from_outside_canvas && (ep == EditAtMouse)) {
4631 ep = EditAtPlayhead;
4632 } else if (from_context_menu && (ep == EditAtMouse)) {
4633 return canvas_event_sample (&context_click_event, 0, 0);
4636 if (entered_marker) {
4637 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4638 return entered_marker->position();
4641 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4642 ep = EditAtSelectedMarker;
4645 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4646 ep = EditAtPlayhead;
4650 case EditAtPlayhead:
4651 if (_dragging_playhead) {
4652 where = *_control_scroll_target;
4654 where = _session->audible_frame();
4656 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4659 case EditAtSelectedMarker:
4660 if (!selection->markers.empty()) {
4662 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4665 where = loc->start();
4669 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4677 if (!mouse_frame (where, ignored)) {
4678 /* XXX not right but what can we do ? */
4682 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4690 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4692 if (!_session) return;
4694 begin_reversible_command (cmd);
4698 if ((tll = transport_loop_location()) == 0) {
4699 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4700 XMLNode &before = _session->locations()->get_state();
4701 _session->locations()->add (loc, true);
4702 _session->set_auto_loop_location (loc);
4703 XMLNode &after = _session->locations()->get_state();
4704 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4706 XMLNode &before = tll->get_state();
4707 tll->set_hidden (false, this);
4708 tll->set (start, end);
4709 XMLNode &after = tll->get_state();
4710 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4713 commit_reversible_command ();
4717 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4719 if (!_session) return;
4721 begin_reversible_command (cmd);
4725 if ((tpl = transport_punch_location()) == 0) {
4726 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4727 XMLNode &before = _session->locations()->get_state();
4728 _session->locations()->add (loc, true);
4729 _session->set_auto_punch_location (loc);
4730 XMLNode &after = _session->locations()->get_state();
4731 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4733 XMLNode &before = tpl->get_state();
4734 tpl->set_hidden (false, this);
4735 tpl->set (start, end);
4736 XMLNode &after = tpl->get_state();
4737 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4740 commit_reversible_command ();
4743 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4744 * @param rs List to which found regions are added.
4745 * @param where Time to look at.
4746 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4749 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4751 const TrackViewList* tracks;
4754 tracks = &track_views;
4759 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4761 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4764 boost::shared_ptr<Track> tr;
4765 boost::shared_ptr<Playlist> pl;
4767 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4769 boost::shared_ptr<RegionList> regions = pl->regions_at (
4770 (framepos_t) floor ( (double) where * tr->speed()));
4772 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4773 RegionView* rv = rtv->view()->find_view (*i);
4784 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4786 const TrackViewList* tracks;
4789 tracks = &track_views;
4794 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4795 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4797 boost::shared_ptr<Track> tr;
4798 boost::shared_ptr<Playlist> pl;
4800 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4802 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4803 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4805 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4807 RegionView* rv = rtv->view()->find_view (*i);
4818 /** Get regions using the following method:
4820 * Make a region list using:
4821 * (a) any selected regions
4822 * (b) the intersection of any selected tracks and the edit point(*)
4823 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4825 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4827 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4831 Editor::get_regions_from_selection_and_edit_point ()
4833 RegionSelection regions;
4835 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4836 regions.add (entered_regionview);
4838 regions = selection->regions;
4841 if ( regions.empty() ) {
4842 TrackViewList tracks = selection->tracks;
4844 if (!tracks.empty()) {
4845 /* no region selected or entered, but some selected tracks:
4846 * act on all regions on the selected tracks at the edit point
4848 framepos_t const where = get_preferred_edit_position ();
4849 get_regions_at(regions, where, tracks);
4856 /** Get regions using the following method:
4858 * Make a region list using:
4859 * (a) any selected regions
4860 * (b) the intersection of any selected tracks and the edit point(*)
4861 * (c) if neither exists, then whatever region is under the mouse
4863 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4865 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4868 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4870 RegionSelection regions;
4872 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4873 regions.add (entered_regionview);
4875 regions = selection->regions;
4878 if ( regions.empty() ) {
4879 TrackViewList tracks = selection->tracks;
4881 if (!tracks.empty()) {
4882 /* no region selected or entered, but some selected tracks:
4883 * act on all regions on the selected tracks at the edit point
4885 get_regions_at(regions, pos, tracks);
4892 /** Start with regions that are selected, or the entered regionview if none are selected.
4893 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4894 * of the regions that we started with.
4898 Editor::get_regions_from_selection_and_entered () const
4900 RegionSelection regions = selection->regions;
4902 if (regions.empty() && entered_regionview) {
4903 regions.add (entered_regionview);
4910 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4912 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4913 RouteTimeAxisView* rtav;
4915 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4916 boost::shared_ptr<Playlist> pl;
4917 std::vector<boost::shared_ptr<Region> > results;
4918 boost::shared_ptr<Track> tr;
4920 if ((tr = rtav->track()) == 0) {
4925 if ((pl = (tr->playlist())) != 0) {
4926 boost::shared_ptr<Region> r = pl->region_by_id (id);
4928 RegionView* rv = rtav->view()->find_view (r);
4930 regions.push_back (rv);
4939 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4942 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4943 MidiTimeAxisView* mtav;
4945 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4947 mtav->get_per_region_note_selection (selection);
4954 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4956 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4958 RouteTimeAxisView* tatv;
4960 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4962 boost::shared_ptr<Playlist> pl;
4963 vector<boost::shared_ptr<Region> > results;
4965 boost::shared_ptr<Track> tr;
4967 if ((tr = tatv->track()) == 0) {
4972 if ((pl = (tr->playlist())) != 0) {
4973 if (src_comparison) {
4974 pl->get_source_equivalent_regions (region, results);
4976 pl->get_region_list_equivalent_regions (region, results);
4980 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4981 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4982 regions.push_back (marv);
4991 Editor::show_rhythm_ferret ()
4993 if (rhythm_ferret == 0) {
4994 rhythm_ferret = new RhythmFerret(*this);
4997 rhythm_ferret->set_session (_session);
4998 rhythm_ferret->show ();
4999 rhythm_ferret->present ();
5003 Editor::first_idle ()
5005 MessageDialog* dialog = 0;
5007 if (track_views.size() > 1) {
5008 Timers::TimerSuspender t;
5009 dialog = new MessageDialog (
5010 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5014 ARDOUR_UI::instance()->flush_pending ();
5017 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5021 // first idle adds route children (automation tracks), so we need to redisplay here
5022 _routes->redisplay ();
5026 if (_session->undo_depth() == 0) {
5027 undo_action->set_sensitive(false);
5029 redo_action->set_sensitive(false);
5030 begin_selection_op_history ();
5036 Editor::_idle_resize (gpointer arg)
5038 return ((Editor*)arg)->idle_resize ();
5042 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5044 if (resize_idle_id < 0) {
5045 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5046 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5047 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5049 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5050 _pending_resize_amount = 0;
5053 /* make a note of the smallest resulting height, so that we can clamp the
5054 lower limit at TimeAxisView::hSmall */
5056 int32_t min_resulting = INT32_MAX;
5058 _pending_resize_amount += h;
5059 _pending_resize_view = view;
5061 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5063 if (selection->tracks.contains (_pending_resize_view)) {
5064 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5065 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5069 if (min_resulting < 0) {
5074 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5075 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5079 /** Handle pending resizing of tracks */
5081 Editor::idle_resize ()
5083 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5085 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5086 selection->tracks.contains (_pending_resize_view)) {
5088 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5089 if (*i != _pending_resize_view) {
5090 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5095 _pending_resize_amount = 0;
5096 _group_tabs->set_dirty ();
5097 resize_idle_id = -1;
5105 ENSURE_GUI_THREAD (*this, &Editor::located);
5108 playhead_cursor->set_position (_session->audible_frame ());
5109 if (_follow_playhead && !_pending_initial_locate) {
5110 reset_x_origin_to_follow_playhead ();
5114 _pending_locate_request = false;
5115 _pending_initial_locate = false;
5119 Editor::region_view_added (RegionView * rv)
5121 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5122 if (rv->region ()->id () == (*pr)) {
5123 selection->add (rv);
5124 selection->regions.pending.erase (pr);
5129 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5131 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5132 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5133 if (rv->region()->id () == (*rnote).first) {
5134 mrv->select_notes ((*rnote).second);
5135 selection->pending_midi_note_selection.erase(rnote);
5141 _summary->set_background_dirty ();
5145 Editor::region_view_removed ()
5147 _summary->set_background_dirty ();
5151 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5153 TrackViewList::const_iterator j = track_views.begin ();
5154 while (j != track_views.end()) {
5155 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5156 if (rtv && rtv->route() == r) {
5167 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5171 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5172 TimeAxisView* tv = axis_view_from_route (*i);
5182 Editor::suspend_route_redisplay ()
5185 _routes->suspend_redisplay();
5190 Editor::resume_route_redisplay ()
5193 _routes->redisplay(); // queue redisplay
5194 _routes->resume_redisplay();
5199 Editor::add_vcas (VCAList& vlist)
5203 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5204 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5207 add_stripables (sl);
5211 Editor::add_routes (RouteList& rlist)
5215 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5219 add_stripables (sl);
5223 Editor::add_stripables (StripableList& sl)
5225 list<TimeAxisView*> new_views;
5226 boost::shared_ptr<VCA> v;
5227 boost::shared_ptr<Route> r;
5228 TrackViewList new_selection;
5229 bool from_scratch = (track_views.size() == 0);
5231 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5233 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5235 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5237 new_views.push_back (vtv);
5239 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5241 if (r->is_auditioner() || r->is_monitor()) {
5245 RouteTimeAxisView* rtv;
5246 DataType dt = r->input()->default_type();
5248 if (dt == ARDOUR::DataType::AUDIO) {
5249 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5251 } else if (dt == ARDOUR::DataType::MIDI) {
5252 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5255 throw unknown_type();
5258 new_views.push_back (rtv);
5259 track_views.push_back (rtv);
5260 new_selection.push_back (rtv);
5262 rtv->effective_gain_display ();
5264 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5265 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5269 if (new_views.size() > 0) {
5270 _routes->time_axis_views_added (new_views);
5271 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5274 /* note: !new_selection.empty() means that we got some routes rather
5278 if (!from_scratch && !new_selection.empty()) {
5279 selection->tracks.clear();
5280 selection->add (new_selection);
5281 begin_selection_op_history();
5284 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5285 show_editor_mixer (true);
5288 editor_list_button.set_sensitive (true);
5292 Editor::timeaxisview_deleted (TimeAxisView *tv)
5294 if (tv == entered_track) {
5298 if (_session && _session->deletion_in_progress()) {
5299 /* the situation is under control */
5303 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5305 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5307 _routes->route_removed (tv);
5309 TimeAxisView::Children c = tv->get_child_list ();
5310 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5311 if (entered_track == i->get()) {
5316 /* remove it from the list of track views */
5318 TrackViewList::iterator i;
5320 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5321 i = track_views.erase (i);
5324 /* update whatever the current mixer strip is displaying, if revelant */
5326 boost::shared_ptr<Route> route;
5329 route = rtav->route ();
5332 if (current_mixer_strip && current_mixer_strip->route() == route) {
5334 TimeAxisView* next_tv;
5336 if (track_views.empty()) {
5338 } else if (i == track_views.end()) {
5339 next_tv = track_views.front();
5346 set_selected_mixer_strip (*next_tv);
5348 /* make the editor mixer strip go away setting the
5349 * button to inactive (which also unticks the menu option)
5352 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5358 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5360 if (apply_to_selection) {
5361 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5363 TrackSelection::iterator j = i;
5366 hide_track_in_display (*i, false);
5371 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5373 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5374 // this will hide the mixer strip
5375 set_selected_mixer_strip (*tv);
5378 _routes->hide_track_in_display (*tv);
5383 Editor::sync_track_view_list_and_routes ()
5385 track_views = TrackViewList (_routes->views ());
5387 _summary->set_background_dirty();
5388 _group_tabs->set_dirty ();
5390 return false; // do not call again (until needed)
5394 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5396 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5401 /** Find a RouteTimeAxisView by the ID of its route */
5403 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5405 RouteTimeAxisView* v;
5407 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5408 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5409 if(v->route()->id() == id) {
5419 Editor::fit_route_group (RouteGroup *g)
5421 TrackViewList ts = axis_views_from_routes (g->route_list ());
5426 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5428 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5431 _session->cancel_audition ();
5435 if (_session->is_auditioning()) {
5436 _session->cancel_audition ();
5437 if (r == last_audition_region) {
5442 _session->audition_region (r);
5443 last_audition_region = r;
5448 Editor::hide_a_region (boost::shared_ptr<Region> r)
5450 r->set_hidden (true);
5454 Editor::show_a_region (boost::shared_ptr<Region> r)
5456 r->set_hidden (false);
5460 Editor::audition_region_from_region_list ()
5462 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5466 Editor::hide_region_from_region_list ()
5468 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5472 Editor::show_region_in_region_list ()
5474 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5478 Editor::step_edit_status_change (bool yn)
5481 start_step_editing ();
5483 stop_step_editing ();
5488 Editor::start_step_editing ()
5490 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5494 Editor::stop_step_editing ()
5496 step_edit_connection.disconnect ();
5500 Editor::check_step_edit ()
5502 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5503 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5505 mtv->check_step_edit ();
5509 return true; // do it again, till we stop
5513 Editor::scroll_press (Direction dir)
5515 ++_scroll_callbacks;
5517 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5518 /* delay the first auto-repeat */
5524 scroll_backward (1);
5532 scroll_up_one_track ();
5536 scroll_down_one_track ();
5540 /* do hacky auto-repeat */
5541 if (!_scroll_connection.connected ()) {
5543 _scroll_connection = Glib::signal_timeout().connect (
5544 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5547 _scroll_callbacks = 0;
5554 Editor::scroll_release ()
5556 _scroll_connection.disconnect ();
5559 /** Queue a change for the Editor viewport x origin to follow the playhead */
5561 Editor::reset_x_origin_to_follow_playhead ()
5563 framepos_t const frame = playhead_cursor->current_frame ();
5565 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5567 if (_session->transport_speed() < 0) {
5569 if (frame > (current_page_samples() / 2)) {
5570 center_screen (frame-(current_page_samples()/2));
5572 center_screen (current_page_samples()/2);
5579 if (frame < leftmost_frame) {
5581 if (_session->transport_rolling()) {
5582 /* rolling; end up with the playhead at the right of the page */
5583 l = frame - current_page_samples ();
5585 /* not rolling: end up with the playhead 1/4 of the way along the page */
5586 l = frame - current_page_samples() / 4;
5590 if (_session->transport_rolling()) {
5591 /* rolling: end up with the playhead on the left of the page */
5594 /* not rolling: end up with the playhead 3/4 of the way along the page */
5595 l = frame - 3 * current_page_samples() / 4;
5603 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5609 Editor::super_rapid_screen_update ()
5611 if (!_session || !_session->engine().running()) {
5615 /* METERING / MIXER STRIPS */
5617 /* update track meters, if required */
5618 if (contents().is_mapped() && meters_running) {
5619 RouteTimeAxisView* rtv;
5620 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5621 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5622 rtv->fast_update ();
5627 /* and any current mixer strip */
5628 if (current_mixer_strip) {
5629 current_mixer_strip->fast_update ();
5632 /* PLAYHEAD AND VIEWPORT */
5634 framepos_t const frame = _session->audible_frame();
5636 /* There are a few reasons why we might not update the playhead / viewport stuff:
5638 * 1. we don't update things when there's a pending locate request, otherwise
5639 * when the editor requests a locate there is a chance that this method
5640 * will move the playhead before the locate request is processed, causing
5642 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5643 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5646 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5648 last_update_frame = frame;
5650 if (!_dragging_playhead) {
5651 playhead_cursor->set_position (frame);
5654 if (!_stationary_playhead) {
5656 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5657 /* We only do this if we aren't already
5658 handling a visual change (ie if
5659 pending_visual_change.being_handled is
5660 false) so that these requests don't stack
5661 up there are too many of them to handle in
5664 reset_x_origin_to_follow_playhead ();
5669 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5670 framepos_t const frame = playhead_cursor->current_frame ();
5671 double target = ((double)frame - (double)current_page_samples()/2.0);
5672 if (target <= 0.0) {
5675 // compare to EditorCursor::set_position()
5676 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5677 double const new_pos = sample_to_pixel_unrounded (target);
5678 if (rint (new_pos) != rint (old_pos)) {
5679 reset_x_origin (pixel_to_sample (floor (new_pos)));
5690 Editor::session_going_away ()
5692 _have_idled = false;
5694 _session_connections.drop_connections ();
5696 super_rapid_screen_update_connection.disconnect ();
5698 selection->clear ();
5699 cut_buffer->clear ();
5701 clicked_regionview = 0;
5702 clicked_axisview = 0;
5703 clicked_routeview = 0;
5704 entered_regionview = 0;
5706 last_update_frame = 0;
5709 playhead_cursor->hide ();
5711 /* rip everything out of the list displays */
5715 _route_groups->clear ();
5717 /* do this first so that deleting a track doesn't reset cms to null
5718 and thus cause a leak.
5721 if (current_mixer_strip) {
5722 if (current_mixer_strip->get_parent() != 0) {
5723 global_hpacker.remove (*current_mixer_strip);
5725 delete current_mixer_strip;
5726 current_mixer_strip = 0;
5729 /* delete all trackviews */
5731 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5734 track_views.clear ();
5736 nudge_clock->set_session (0);
5738 editor_list_button.set_active(false);
5739 editor_list_button.set_sensitive(false);
5741 /* clear tempo/meter rulers */
5742 remove_metric_marks ();
5744 clear_marker_display ();
5746 stop_step_editing ();
5750 /* get rid of any existing editor mixer strip */
5752 WindowTitle title(Glib::get_application_name());
5753 title += _("Editor");
5755 own_window()->set_title (title.get_string());
5758 SessionHandlePtr::session_going_away ();
5762 Editor::trigger_script (int i)
5764 LuaInstance::instance()-> call_action (i);
5768 Editor::set_script_action_name (int i, const std::string& n)
5770 string const a = string_compose (X_("script-action-%1"), i + 1);
5771 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5774 act->set_label (string_compose (_("Unset #%1"), i + 1));
5775 act->set_tooltip (_("no action bound"));
5776 act->set_sensitive (false);
5779 act->set_tooltip (n);
5780 act->set_sensitive (true);
5782 KeyEditor::UpdateBindings ();
5786 Editor::show_editor_list (bool yn)
5789 _the_notebook.show ();
5791 _the_notebook.hide ();
5796 Editor::change_region_layering_order (bool from_context_menu)
5798 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5800 if (!clicked_routeview) {
5801 if (layering_order_editor) {
5802 layering_order_editor->hide ();
5807 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5813 boost::shared_ptr<Playlist> pl = track->playlist();
5819 if (layering_order_editor == 0) {
5820 layering_order_editor = new RegionLayeringOrderEditor (*this);
5823 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5824 layering_order_editor->maybe_present ();
5828 Editor::update_region_layering_order_editor ()
5830 if (layering_order_editor && layering_order_editor->is_visible ()) {
5831 change_region_layering_order (true);
5836 Editor::setup_fade_images ()
5838 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5839 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5840 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5841 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5842 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5844 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5845 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5846 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5847 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5848 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5850 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5851 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5852 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5853 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5854 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5856 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5857 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5858 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5859 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5860 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5864 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5866 Editor::action_menu_item (std::string const & name)
5868 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5871 return *manage (a->create_menu_item ());
5875 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5877 EventBox* b = manage (new EventBox);
5878 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5879 Label* l = manage (new Label (name));
5883 _the_notebook.append_page (widget, *b);
5887 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5889 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5890 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5893 if (ev->type == GDK_2BUTTON_PRESS) {
5895 /* double-click on a notebook tab shrinks or expands the notebook */
5897 if (_notebook_shrunk) {
5898 if (pre_notebook_shrink_pane_width) {
5899 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
5901 _notebook_shrunk = false;
5903 pre_notebook_shrink_pane_width = edit_pane.get_divider();
5905 /* this expands the LHS of the edit pane to cover the notebook
5906 PAGE but leaves the tabs visible.
5908 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
5909 _notebook_shrunk = true;
5917 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5919 using namespace Menu_Helpers;
5921 MenuList& items = _control_point_context_menu.items ();
5924 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5925 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5926 if (!can_remove_control_point (item)) {
5927 items.back().set_sensitive (false);
5930 _control_point_context_menu.popup (event->button.button, event->button.time);
5934 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5936 using namespace Menu_Helpers;
5938 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5943 /* We need to get the selection here and pass it to the operations, since
5944 popping up the menu will cause a region leave event which clears
5945 entered_regionview. */
5947 MidiRegionView& mrv = note->region_view();
5948 const RegionSelection rs = get_regions_from_selection_and_entered ();
5949 const uint32_t sel_size = mrv.selection_size ();
5951 MenuList& items = _note_context_menu.items();
5955 items.push_back(MenuElem(_("Delete"),
5956 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5959 items.push_back(MenuElem(_("Edit..."),
5960 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5961 if (sel_size != 1) {
5962 items.back().set_sensitive (false);
5965 items.push_back(MenuElem(_("Transpose..."),
5966 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
5969 items.push_back(MenuElem(_("Legatize"),
5970 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5972 items.back().set_sensitive (false);
5975 items.push_back(MenuElem(_("Quantize..."),
5976 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5978 items.push_back(MenuElem(_("Remove Overlap"),
5979 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5981 items.back().set_sensitive (false);
5984 items.push_back(MenuElem(_("Transform..."),
5985 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5987 _note_context_menu.popup (event->button.button, event->button.time);
5991 Editor::zoom_vertical_modifier_released()
5993 _stepping_axis_view = 0;
5997 Editor::ui_parameter_changed (string parameter)
5999 if (parameter == "icon-set") {
6000 while (!_cursor_stack.empty()) {
6001 _cursor_stack.pop_back();
6003 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6004 _cursor_stack.push_back(_cursors->grabber);
6005 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6006 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6008 } else if (parameter == "draggable-playhead") {
6009 if (_verbose_cursor) {
6010 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6016 Editor::use_own_window (bool and_fill_it)
6018 bool new_window = !own_window();
6020 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6022 if (win && new_window) {
6023 win->set_name ("EditorWindow");
6025 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6027 // win->signal_realize().connect (*this, &Editor::on_realize);
6028 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6029 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6030 win->set_data ("ardour-bindings", bindings);
6035 DisplaySuspender ds;
6036 contents().show_all ();
6038 /* XXX: this is a bit unfortunate; it would probably
6039 be nicer if we could just call show () above rather
6040 than needing the show_all ()
6043 /* re-hide stuff if necessary */
6044 editor_list_button_toggled ();
6045 parameter_changed ("show-summary");
6046 parameter_changed ("show-group-tabs");
6047 parameter_changed ("show-zoom-tools");
6049 /* now reset all audio_time_axis heights, because widgets might need
6055 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6056 tv = (static_cast<TimeAxisView*>(*i));
6057 tv->reset_height ();
6060 if (current_mixer_strip) {
6061 current_mixer_strip->hide_things ();
6062 current_mixer_strip->parameter_changed ("mixer-element-visibility");