2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include <gtkmm2ext/keyboard.h>
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
68 #include "ardour/analysis_graph.h"
69 #include "ardour/audio_track.h"
70 #include "ardour/audioengine.h"
71 #include "ardour/audioregion.h"
72 #include "ardour/lmath.h"
73 #include "ardour/location.h"
74 #include "ardour/profile.h"
75 #include "ardour/route_group.h"
76 #include "ardour/session_playlists.h"
77 #include "ardour/tempo.h"
78 #include "ardour/utils.h"
79 #include "ardour/vca_manager.h"
81 #include "canvas/debug.h"
82 #include "canvas/text.h"
84 #include "control_protocol/control_protocol.h"
87 #include "analysis_window.h"
88 #include "audio_clock.h"
89 #include "audio_region_view.h"
90 #include "audio_streamview.h"
91 #include "audio_time_axis.h"
92 #include "automation_time_axis.h"
93 #include "bundle_manager.h"
94 #include "crossfade_edit.h"
98 #include "editor_cursors.h"
99 #include "editor_drag.h"
100 #include "editor_group_tabs.h"
101 #include "editor_locations.h"
102 #include "editor_regions.h"
103 #include "editor_route_groups.h"
104 #include "editor_routes.h"
105 #include "editor_snapshots.h"
106 #include "editor_summary.h"
107 #include "export_report.h"
108 #include "global_port_matrix.h"
109 #include "gui_object.h"
110 #include "gui_thread.h"
111 #include "keyboard.h"
112 #include "keyeditor.h"
113 #include "luainstance.h"
115 #include "midi_region_view.h"
116 #include "midi_time_axis.h"
117 #include "mixer_strip.h"
118 #include "mixer_ui.h"
119 #include "mouse_cursors.h"
120 #include "note_base.h"
121 #include "playlist_selector.h"
122 #include "public_editor.h"
123 #include "quantize_dialog.h"
124 #include "region_layering_order_editor.h"
125 #include "rgb_macros.h"
126 #include "rhythm_ferret.h"
127 #include "selection.h"
128 #include "simple_progress_dialog.h"
130 #include "tempo_lines.h"
131 #include "time_axis_view.h"
133 #include "tooltips.h"
134 #include "ui_config.h"
136 #include "vca_time_axis.h"
137 #include "verbose_cursor.h"
142 using namespace ARDOUR;
143 using namespace ARDOUR_UI_UTILS;
146 using namespace Glib;
147 using namespace Gtkmm2ext;
148 using namespace Editing;
150 using PBD::internationalize;
152 using Gtkmm2ext::Keyboard;
154 double Editor::timebar_height = 15.0;
156 static const gchar *_snap_type_strings[] = {
190 static const gchar *_snap_mode_strings[] = {
197 static const gchar *_edit_point_strings[] = {
204 static const gchar *_edit_mode_strings[] = {
212 static const gchar *_zoom_focus_strings[] = {
222 #ifdef USE_RUBBERBAND
223 static const gchar *_rb_opt_strings[] = {
226 N_("Balanced multitimbral mixture"),
227 N_("Unpitched percussion with stable notes"),
228 N_("Crisp monophonic instrumental"),
229 N_("Unpitched solo percussion"),
230 N_("Resample without preserving pitch"),
235 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
238 : PublicEditor (global_hpacker)
239 , editor_mixer_strip_width (Wide)
240 , constructed (false)
241 , _playlist_selector (0)
242 , no_save_visual (false)
244 , samples_per_pixel (2048)
245 , zoom_focus (ZoomFocusPlayhead)
246 , mouse_mode (MouseObject)
247 , pre_internal_snap_type (SnapToBeat)
248 , pre_internal_snap_mode (SnapOff)
249 , internal_snap_type (SnapToBeat)
250 , internal_snap_mode (SnapOff)
251 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
252 , _notebook_shrunk (false)
253 , location_marker_color (0)
254 , location_range_color (0)
255 , location_loop_color (0)
256 , location_punch_color (0)
257 , location_cd_marker_color (0)
259 , _show_marker_lines (false)
260 , clicked_axisview (0)
261 , clicked_routeview (0)
262 , clicked_regionview (0)
263 , clicked_selection (0)
264 , clicked_control_point (0)
265 , button_release_can_deselect (true)
266 , _mouse_changed_selection (false)
267 , region_edit_menu_split_item (0)
268 , region_edit_menu_split_multichannel_item (0)
269 , track_region_edit_playlist_menu (0)
270 , track_edit_playlist_submenu (0)
271 , track_selection_edit_playlist_submenu (0)
272 , _popup_region_menu_item (0)
274 , _track_canvas_viewport (0)
275 , within_track_canvas (false)
276 , _verbose_cursor (0)
280 , range_marker_group (0)
281 , transport_marker_group (0)
282 , cd_marker_group (0)
283 , _time_markers_group (0)
284 , hv_scroll_group (0)
286 , cursor_scroll_group (0)
287 , no_scroll_group (0)
288 , _trackview_group (0)
289 , _drag_motion_group (0)
290 , _canvas_drop_zone (0)
291 , no_ruler_shown_update (false)
292 , ruler_grabbed_widget (0)
294 , minsec_mark_interval (0)
295 , minsec_mark_modulo (0)
297 , timecode_mark_modulo (0)
298 , timecode_nmarks (0)
299 , _samples_ruler_interval (0)
302 , bbt_bar_helper_on (0)
303 , bbt_accent_modulo (0)
308 , visible_timebars (0)
309 , editor_ruler_menu (0)
313 , range_marker_bar (0)
314 , transport_marker_bar (0)
316 , minsec_label (_("Mins:Secs"))
317 , bbt_label (_("Bars:Beats"))
318 , timecode_label (_("Timecode"))
319 , samples_label (_("Samples"))
320 , tempo_label (_("Tempo"))
321 , meter_label (_("Meter"))
322 , mark_label (_("Location Markers"))
323 , range_mark_label (_("Range Markers"))
324 , transport_mark_label (_("Loop/Punch Ranges"))
325 , cd_mark_label (_("CD Markers"))
326 , videotl_label (_("Video Timeline"))
328 , playhead_cursor (0)
329 , edit_packer (4, 4, true)
330 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
331 , horizontal_adjustment (0.0, 0.0, 1e16)
332 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
333 , controls_layout (unused_adjustment, vertical_adjustment)
334 , _scroll_callbacks (0)
335 , _visible_canvas_width (0)
336 , _visible_canvas_height (0)
337 , _full_canvas_height (0)
338 , edit_controls_left_menu (0)
339 , edit_controls_right_menu (0)
340 , last_update_frame (0)
341 , cut_buffer_start (0)
342 , cut_buffer_length (0)
343 , button_bindings (0)
347 , current_interthread_info (0)
348 , analysis_window (0)
349 , select_new_marker (false)
351 , scrubbing_direction (0)
352 , scrub_reversals (0)
353 , scrub_reverse_distance (0)
354 , have_pending_keyboard_selection (false)
355 , pending_keyboard_selection_start (0)
356 , _snap_type (SnapToBeat)
357 , _snap_mode (SnapOff)
358 , snap_threshold (5.0)
359 , ignore_gui_changes (false)
360 , _drags (new DragManager (this))
362 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
363 , _dragging_playhead (false)
364 , _dragging_edit_point (false)
365 , _show_measures (true)
366 , _follow_playhead (true)
367 , _stationary_playhead (false)
370 , global_rect_group (0)
371 , time_line_group (0)
372 , tempo_marker_menu (0)
373 , meter_marker_menu (0)
375 , range_marker_menu (0)
376 , transport_marker_menu (0)
377 , new_transport_marker_menu (0)
379 , marker_menu_item (0)
380 , bbt_beat_subdivision (4)
381 , _visible_track_count (-1)
382 , toolbar_selection_clock_table (2,3)
383 , automation_mode_button (_("mode"))
384 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
385 , selection (new Selection (this))
386 , cut_buffer (new Selection (this))
387 , _selection_memento (new SelectionMemento())
388 , _all_region_actions_sensitized (false)
389 , _ignore_region_action (false)
390 , _last_region_menu_was_main (false)
391 , _ignore_follow_edits (false)
392 , cd_marker_bar_drag_rect (0)
393 , range_bar_drag_rect (0)
394 , transport_bar_drag_rect (0)
395 , transport_bar_range_rect (0)
396 , transport_bar_preroll_rect (0)
397 , transport_bar_postroll_rect (0)
398 , transport_loop_range_rect (0)
399 , transport_punch_range_rect (0)
400 , transport_punchin_line (0)
401 , transport_punchout_line (0)
402 , transport_preroll_rect (0)
403 , transport_postroll_rect (0)
405 , rubberband_rect (0)
411 , autoscroll_horizontal_allowed (false)
412 , autoscroll_vertical_allowed (false)
414 , autoscroll_widget (0)
415 , show_gain_after_trim (false)
416 , selection_op_cmd_depth (0)
417 , selection_op_history_it (0)
418 , no_save_instant (false)
420 , current_mixer_strip (0)
421 , show_editor_mixer_when_tracks_arrive (false)
422 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
423 , current_stepping_trackview (0)
424 , last_track_height_step_timestamp (0)
426 , entered_regionview (0)
427 , clear_entered_track (false)
428 , _edit_point (EditAtMouse)
429 , meters_running (false)
431 , _have_idled (false)
432 , resize_idle_id (-1)
433 , _pending_resize_amount (0)
434 , _pending_resize_view (0)
435 , _pending_locate_request (false)
436 , _pending_initial_locate (false)
440 , layering_order_editor (0)
441 , _last_cut_copy_source_track (0)
442 , _region_selection_change_updates_region_list (true)
444 , _following_mixer_selection (false)
445 , _control_point_toggled_on_press (false)
446 , _stepping_axis_view (0)
447 , quantize_dialog (0)
448 , _main_menu_disabler (0)
449 , myactions (X_("editor"))
451 /* we are a singleton */
453 PublicEditor::_instance = this;
457 last_event_time.tv_sec = 0;
458 last_event_time.tv_usec = 0;
460 selection_op_history.clear();
463 snap_type_strings = I18N (_snap_type_strings);
464 snap_mode_strings = I18N (_snap_mode_strings);
465 zoom_focus_strings = I18N (_zoom_focus_strings);
466 edit_mode_strings = I18N (_edit_mode_strings);
467 edit_point_strings = I18N (_edit_point_strings);
468 #ifdef USE_RUBBERBAND
469 rb_opt_strings = I18N (_rb_opt_strings);
473 build_edit_mode_menu();
474 build_zoom_focus_menu();
475 build_track_count_menu();
476 build_snap_mode_menu();
477 build_snap_type_menu();
478 build_edit_point_menu();
480 location_marker_color = UIConfiguration::instance().color ("location marker");
481 location_range_color = UIConfiguration::instance().color ("location range");
482 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
483 location_loop_color = UIConfiguration::instance().color ("location loop");
484 location_punch_color = UIConfiguration::instance().color ("location punch");
486 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
488 TimeAxisView::setup_sizes ();
489 ArdourMarker::setup_sizes (timebar_height);
490 TempoCurve::setup_sizes (timebar_height);
492 bbt_label.set_name ("EditorRulerLabel");
493 bbt_label.set_size_request (-1, (int)timebar_height);
494 bbt_label.set_alignment (1.0, 0.5);
495 bbt_label.set_padding (5,0);
497 bbt_label.set_no_show_all();
498 minsec_label.set_name ("EditorRulerLabel");
499 minsec_label.set_size_request (-1, (int)timebar_height);
500 minsec_label.set_alignment (1.0, 0.5);
501 minsec_label.set_padding (5,0);
502 minsec_label.hide ();
503 minsec_label.set_no_show_all();
504 timecode_label.set_name ("EditorRulerLabel");
505 timecode_label.set_size_request (-1, (int)timebar_height);
506 timecode_label.set_alignment (1.0, 0.5);
507 timecode_label.set_padding (5,0);
508 timecode_label.hide ();
509 timecode_label.set_no_show_all();
510 samples_label.set_name ("EditorRulerLabel");
511 samples_label.set_size_request (-1, (int)timebar_height);
512 samples_label.set_alignment (1.0, 0.5);
513 samples_label.set_padding (5,0);
514 samples_label.hide ();
515 samples_label.set_no_show_all();
517 tempo_label.set_name ("EditorRulerLabel");
518 tempo_label.set_size_request (-1, (int)timebar_height);
519 tempo_label.set_alignment (1.0, 0.5);
520 tempo_label.set_padding (5,0);
522 tempo_label.set_no_show_all();
524 meter_label.set_name ("EditorRulerLabel");
525 meter_label.set_size_request (-1, (int)timebar_height);
526 meter_label.set_alignment (1.0, 0.5);
527 meter_label.set_padding (5,0);
529 meter_label.set_no_show_all();
531 if (Profile->get_trx()) {
532 mark_label.set_text (_("Markers"));
534 mark_label.set_name ("EditorRulerLabel");
535 mark_label.set_size_request (-1, (int)timebar_height);
536 mark_label.set_alignment (1.0, 0.5);
537 mark_label.set_padding (5,0);
539 mark_label.set_no_show_all();
541 cd_mark_label.set_name ("EditorRulerLabel");
542 cd_mark_label.set_size_request (-1, (int)timebar_height);
543 cd_mark_label.set_alignment (1.0, 0.5);
544 cd_mark_label.set_padding (5,0);
545 cd_mark_label.hide();
546 cd_mark_label.set_no_show_all();
548 videotl_bar_height = 4;
549 videotl_label.set_name ("EditorRulerLabel");
550 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
551 videotl_label.set_alignment (1.0, 0.5);
552 videotl_label.set_padding (5,0);
553 videotl_label.hide();
554 videotl_label.set_no_show_all();
556 range_mark_label.set_name ("EditorRulerLabel");
557 range_mark_label.set_size_request (-1, (int)timebar_height);
558 range_mark_label.set_alignment (1.0, 0.5);
559 range_mark_label.set_padding (5,0);
560 range_mark_label.hide();
561 range_mark_label.set_no_show_all();
563 transport_mark_label.set_name ("EditorRulerLabel");
564 transport_mark_label.set_size_request (-1, (int)timebar_height);
565 transport_mark_label.set_alignment (1.0, 0.5);
566 transport_mark_label.set_padding (5,0);
567 transport_mark_label.hide();
568 transport_mark_label.set_no_show_all();
570 initialize_canvas ();
572 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
574 _summary = new EditorSummary (this);
576 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
577 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
579 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
581 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
582 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
584 edit_controls_vbox.set_spacing (0);
585 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
586 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
588 HBox* h = manage (new HBox);
589 _group_tabs = new EditorGroupTabs (this);
590 if (!ARDOUR::Profile->get_trx()) {
591 h->pack_start (*_group_tabs, PACK_SHRINK);
593 h->pack_start (edit_controls_vbox);
594 controls_layout.add (*h);
596 controls_layout.set_name ("EditControlsBase");
597 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
598 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
599 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
601 _cursors = new MouseCursors;
602 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
603 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
605 /* Push default cursor to ever-present bottom of cursor stack. */
606 push_canvas_cursor(_cursors->grabber);
608 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
610 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
611 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
612 pad_line_1->set_outline_color (0xFF0000FF);
618 edit_packer.set_col_spacings (0);
619 edit_packer.set_row_spacings (0);
620 edit_packer.set_homogeneous (false);
621 edit_packer.set_border_width (0);
622 edit_packer.set_name ("EditorWindow");
624 time_bars_event_box.add (time_bars_vbox);
625 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
626 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
628 /* labels for the time bars */
629 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
631 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
633 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
635 bottom_hbox.set_border_width (2);
636 bottom_hbox.set_spacing (3);
638 _route_groups = new EditorRouteGroups (this);
639 _routes = new EditorRoutes (this);
640 _regions = new EditorRegions (this);
641 _snapshots = new EditorSnapshots (this);
642 _locations = new EditorLocations (this);
644 /* these are static location signals */
646 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
647 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
648 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
650 add_notebook_page (_("Regions"), _regions->widget ());
651 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
652 add_notebook_page (_("Snapshots"), _snapshots->widget ());
653 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
654 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
656 _the_notebook.set_show_tabs (true);
657 _the_notebook.set_scrollable (true);
658 _the_notebook.popup_disable ();
659 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
660 _the_notebook.show_all ();
662 _notebook_shrunk = false;
665 /* Pick up some settings we need to cache, early */
667 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
670 if (settings && (prop = settings->property ("notebook-shrunk"))) {
671 _notebook_shrunk = string_is_affirmative (prop->value ());
674 editor_summary_pane.add (edit_packer);
676 Button* summary_arrows_left_left = manage (new Button);
677 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
678 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
679 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
681 Button* summary_arrows_left_right = manage (new Button);
682 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
683 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
684 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
686 VBox* summary_arrows_left = manage (new VBox);
687 summary_arrows_left->pack_start (*summary_arrows_left_left);
688 summary_arrows_left->pack_start (*summary_arrows_left_right);
690 Button* summary_arrows_right_up = manage (new Button);
691 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
692 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
693 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
695 Button* summary_arrows_right_down = manage (new Button);
696 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
697 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
698 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
700 VBox* summary_arrows_right = manage (new VBox);
701 summary_arrows_right->pack_start (*summary_arrows_right_up);
702 summary_arrows_right->pack_start (*summary_arrows_right_down);
704 Frame* summary_frame = manage (new Frame);
705 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
707 summary_frame->add (*_summary);
708 summary_frame->show ();
710 _summary_hbox.pack_start (*summary_arrows_left, false, false);
711 _summary_hbox.pack_start (*summary_frame, true, true);
712 _summary_hbox.pack_start (*summary_arrows_right, false, false);
714 if (!ARDOUR::Profile->get_trx()) {
715 editor_summary_pane.add (_summary_hbox);
718 edit_pane.add (editor_summary_pane);
719 if (!ARDOUR::Profile->get_trx()) {
720 edit_pane.add (_the_notebook);
723 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
724 edit_pane.set_child_minsize (_the_notebook, 30); /* rough guess at width of notebook tabs */
725 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
727 if (!settings || (prop = settings->property ("edit-horizontal-pane-pos")) == 0) {
728 /* initial allocation is 90% to canvas, 10% to notebook */
729 edit_pane.set_divider (0, 0.90);
731 edit_pane.set_divider (0, atof (prop->value()));
734 if (!settings || (prop = settings->property ("edit-vertical-pane-pos")) == 0) {
735 /* initial allocation is 90% to canvas, 10% to summary */
736 editor_summary_pane.set_divider (0, 0.90);
739 editor_summary_pane.set_divider (0, atof (prop->value()));
742 top_hbox.pack_start (toolbar_frame);
744 HBox *hbox = manage (new HBox);
745 hbox->pack_start (edit_pane, true, true);
747 global_vpacker.pack_start (top_hbox, false, false);
748 global_vpacker.pack_start (*hbox, true, true);
749 global_hpacker.pack_start (global_vpacker, true, true);
751 /* need to show the "contents" widget so that notebook will show if tab is switched to
754 global_hpacker.show ();
756 /* register actions now so that set_state() can find them and set toggles/checks etc */
763 _playlist_selector = new PlaylistSelector();
764 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
766 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
770 nudge_forward_button.set_name ("nudge button");
771 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
773 nudge_backward_button.set_name ("nudge button");
774 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
776 fade_context_menu.set_name ("ArdourContextMenu");
778 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
780 /* allow external control surfaces/protocols to do various things */
782 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
783 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
784 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
785 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
786 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
787 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
788 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
789 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
790 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
791 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
792 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
793 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
794 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
795 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
797 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
798 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
799 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
800 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
801 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
803 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
807 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
809 /* problematic: has to return a value and thus cannot be x-thread */
811 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
813 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
814 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
816 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
818 _ignore_region_action = false;
819 _last_region_menu_was_main = false;
820 _popup_region_menu_item = 0;
822 _ignore_follow_edits = false;
824 _show_marker_lines = false;
826 /* Button bindings */
828 button_bindings = new Bindings ("editor-mouse");
830 XMLNode* node = button_settings();
832 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
833 button_bindings->load_operation (**i);
839 /* grab current parameter state */
840 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
841 UIConfiguration::instance().map_parameters (pc);
843 setup_fade_images ();
845 LuaInstance::instance(); // instantiate
846 LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &Editor::set_script_action_name));
853 delete button_bindings;
855 delete _route_groups;
856 delete _track_canvas_viewport;
859 delete quantize_dialog;
865 delete _playlist_selector;
867 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
873 Editor::button_settings () const
875 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
876 XMLNode* node = find_named_node (*settings, X_("Buttons"));
879 node = new XMLNode (X_("Buttons"));
886 Editor::get_smart_mode () const
888 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
892 Editor::catch_vanishing_regionview (RegionView *rv)
894 /* note: the selection will take care of the vanishing
895 audioregionview by itself.
898 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
902 if (clicked_regionview == rv) {
903 clicked_regionview = 0;
906 if (entered_regionview == rv) {
907 set_entered_regionview (0);
910 if (!_all_region_actions_sensitized) {
911 sensitize_all_region_actions (true);
916 Editor::set_entered_regionview (RegionView* rv)
918 if (rv == entered_regionview) {
922 if (entered_regionview) {
923 entered_regionview->exited ();
926 entered_regionview = rv;
928 if (entered_regionview != 0) {
929 entered_regionview->entered ();
932 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
933 /* This RegionView entry might have changed what region actions
934 are allowed, so sensitize them all in case a key is pressed.
936 sensitize_all_region_actions (true);
941 Editor::set_entered_track (TimeAxisView* tav)
944 entered_track->exited ();
950 entered_track->entered ();
955 Editor::instant_save ()
957 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
962 _session->add_instant_xml(get_state());
964 Config->add_instant_xml(get_state());
969 Editor::control_vertical_zoom_in_all ()
971 tav_zoom_smooth (false, true);
975 Editor::control_vertical_zoom_out_all ()
977 tav_zoom_smooth (true, true);
981 Editor::control_vertical_zoom_in_selected ()
983 tav_zoom_smooth (false, false);
987 Editor::control_vertical_zoom_out_selected ()
989 tav_zoom_smooth (true, false);
993 Editor::control_view (uint32_t view)
995 goto_visual_state (view);
999 Editor::control_unselect ()
1001 selection->clear_tracks ();
1005 Editor::control_select (PresentationInfo::global_order_t global_order, Selection::Operation op)
1007 /* handles the (static) signal from the ControlProtocol class that
1008 * requests setting the selected track to a given RID
1015 PresentationInfo::Flag select_flags;
1017 if (global_order & ~0xffffffff) {
1018 /* some flags are set, so the PresentationInfo constructor
1021 select_flags = PresentationInfo::Flag (0);
1023 /* no type flags set in the global order ID, so assume caller
1024 * wants to select a Route
1026 select_flags = PresentationInfo::Route;
1029 PresentationInfo pi (global_order, select_flags);
1030 boost::shared_ptr<Stripable> s = _session->get_remote_nth_stripable (pi.group_order(), pi.flags());
1032 /* selected object may not be a Route */
1034 boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route> (s);
1040 TimeAxisView* tav = axis_view_from_route (r);
1044 case Selection::Add:
1045 selection->add (tav);
1047 case Selection::Toggle:
1048 selection->toggle (tav);
1050 case Selection::Extend:
1052 case Selection::Set:
1053 selection->set (tav);
1057 selection->clear_tracks ();
1062 Editor::control_step_tracks_up ()
1064 scroll_tracks_up_line ();
1068 Editor::control_step_tracks_down ()
1070 scroll_tracks_down_line ();
1074 Editor::control_scroll (float fraction)
1076 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1082 double step = fraction * current_page_samples();
1085 _control_scroll_target is an optional<T>
1087 it acts like a pointer to an framepos_t, with
1088 a operator conversion to boolean to check
1089 that it has a value could possibly use
1090 playhead_cursor->current_frame to store the
1091 value and a boolean in the class to know
1092 when it's out of date
1095 if (!_control_scroll_target) {
1096 _control_scroll_target = _session->transport_frame();
1097 _dragging_playhead = true;
1100 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1101 *_control_scroll_target = 0;
1102 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1103 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1105 *_control_scroll_target += (framepos_t) trunc (step);
1108 /* move visuals, we'll catch up with it later */
1110 playhead_cursor->set_position (*_control_scroll_target);
1111 UpdateAllTransportClocks (*_control_scroll_target);
1113 if (*_control_scroll_target > (current_page_samples() / 2)) {
1114 /* try to center PH in window */
1115 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1121 Now we do a timeout to actually bring the session to the right place
1122 according to the playhead. This is to avoid reading disk buffers on every
1123 call to control_scroll, which is driven by ScrollTimeline and therefore
1124 probably by a control surface wheel which can generate lots of events.
1126 /* cancel the existing timeout */
1128 control_scroll_connection.disconnect ();
1130 /* add the next timeout */
1132 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1136 Editor::deferred_control_scroll (framepos_t /*target*/)
1138 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1139 // reset for next stream
1140 _control_scroll_target = boost::none;
1141 _dragging_playhead = false;
1146 Editor::access_action (std::string action_group, std::string action_item)
1152 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1155 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1163 Editor::on_realize ()
1167 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1168 start_lock_event_timing ();
1173 Editor::start_lock_event_timing ()
1175 /* check if we should lock the GUI every 30 seconds */
1177 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1181 Editor::generic_event_handler (GdkEvent* ev)
1184 case GDK_BUTTON_PRESS:
1185 case GDK_BUTTON_RELEASE:
1186 case GDK_MOTION_NOTIFY:
1188 case GDK_KEY_RELEASE:
1189 if (contents().is_mapped()) {
1190 gettimeofday (&last_event_time, 0);
1194 case GDK_LEAVE_NOTIFY:
1195 switch (ev->crossing.detail) {
1196 case GDK_NOTIFY_UNKNOWN:
1197 case GDK_NOTIFY_INFERIOR:
1198 case GDK_NOTIFY_ANCESTOR:
1200 case GDK_NOTIFY_VIRTUAL:
1201 case GDK_NOTIFY_NONLINEAR:
1202 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1203 /* leaving window, so reset focus, thus ending any and
1204 all text entry operations.
1206 reset_focus (&contents());
1219 Editor::lock_timeout_callback ()
1221 struct timeval now, delta;
1223 gettimeofday (&now, 0);
1225 timersub (&now, &last_event_time, &delta);
1227 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1229 /* don't call again. Returning false will effectively
1230 disconnect us from the timer callback.
1232 unlock() will call start_lock_event_timing() to get things
1242 Editor::map_position_change (framepos_t frame)
1244 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1246 if (_session == 0) {
1250 if (_follow_playhead) {
1251 center_screen (frame);
1254 playhead_cursor->set_position (frame);
1258 Editor::center_screen (framepos_t frame)
1260 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1262 /* if we're off the page, then scroll.
1265 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1266 center_screen_internal (frame, page);
1271 Editor::center_screen_internal (framepos_t frame, float page)
1276 frame -= (framepos_t) page;
1281 reset_x_origin (frame);
1286 Editor::update_title ()
1288 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1290 if (!own_window()) {
1295 bool dirty = _session->dirty();
1297 string session_name;
1299 if (_session->snap_name() != _session->name()) {
1300 session_name = _session->snap_name();
1302 session_name = _session->name();
1306 session_name = "*" + session_name;
1309 WindowTitle title(session_name);
1310 title += S_("Window|Editor");
1311 title += Glib::get_application_name();
1312 own_window()->set_title (title.get_string());
1314 /* ::session_going_away() will have taken care of it */
1319 Editor::set_session (Session *t)
1321 SessionHandlePtr::set_session (t);
1327 _playlist_selector->set_session (_session);
1328 nudge_clock->set_session (_session);
1329 _summary->set_session (_session);
1330 _group_tabs->set_session (_session);
1331 _route_groups->set_session (_session);
1332 _regions->set_session (_session);
1333 _snapshots->set_session (_session);
1334 _routes->set_session (_session);
1335 _locations->set_session (_session);
1337 if (rhythm_ferret) {
1338 rhythm_ferret->set_session (_session);
1341 if (analysis_window) {
1342 analysis_window->set_session (_session);
1346 sfbrowser->set_session (_session);
1349 compute_fixed_ruler_scale ();
1351 /* Make sure we have auto loop and auto punch ranges */
1353 Location* loc = _session->locations()->auto_loop_location();
1355 loc->set_name (_("Loop"));
1358 loc = _session->locations()->auto_punch_location();
1361 loc->set_name (_("Punch"));
1364 refresh_location_display ();
1366 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1367 the selected Marker; this needs the LocationMarker list to be available.
1369 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1370 set_state (*node, Stateful::loading_state_version);
1372 /* catch up with the playhead */
1374 _session->request_locate (playhead_cursor->current_frame ());
1375 _pending_initial_locate = true;
1379 /* These signals can all be emitted by a non-GUI thread. Therefore the
1380 handlers for them must not attempt to directly interact with the GUI,
1381 but use PBD::Signal<T>::connect() which accepts an event loop
1382 ("context") where the handler will be asked to run.
1385 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1386 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1387 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1388 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1389 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1390 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1391 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1392 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::marker_position_changed, this), gui_context());
1393 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1394 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1395 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1396 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1397 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1398 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1399 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1401 playhead_cursor->show ();
1403 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1404 Config->map_parameters (pc);
1405 _session->config.map_parameters (pc);
1407 restore_ruler_visibility ();
1408 //tempo_map_changed (PropertyChange (0));
1409 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1411 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1412 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1415 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1416 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1419 switch (_snap_type) {
1420 case SnapToRegionStart:
1421 case SnapToRegionEnd:
1422 case SnapToRegionSync:
1423 case SnapToRegionBoundary:
1424 build_region_boundary_cache ();
1431 /* register for undo history */
1432 _session->register_with_memento_command_factory(id(), this);
1433 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1435 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1437 LuaInstance::instance()->set_session(_session);
1439 start_updating_meters ();
1443 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1445 if (a->get_name() == "RegionMenu") {
1446 /* When the main menu's region menu is opened, we setup the actions so that they look right
1447 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1448 so we resensitize all region actions when the entered regionview or the region selection
1449 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1450 happens after the region context menu is opened. So we set a flag here, too.
1454 sensitize_the_right_region_actions ();
1455 _last_region_menu_was_main = true;
1460 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1462 using namespace Menu_Helpers;
1464 void (Editor::*emf)(FadeShape);
1465 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1468 images = &_xfade_in_images;
1469 emf = &Editor::set_fade_in_shape;
1471 images = &_xfade_out_images;
1472 emf = &Editor::set_fade_out_shape;
1477 _("Linear (for highly correlated material)"),
1478 *(*images)[FadeLinear],
1479 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1483 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1487 _("Constant power"),
1488 *(*images)[FadeConstantPower],
1489 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1492 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1497 *(*images)[FadeSymmetric],
1498 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1502 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1507 *(*images)[FadeSlow],
1508 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1511 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1516 *(*images)[FadeFast],
1517 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1520 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1523 /** Pop up a context menu for when the user clicks on a start crossfade */
1525 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1527 using namespace Menu_Helpers;
1528 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1533 MenuList& items (xfade_in_context_menu.items());
1536 if (arv->audio_region()->fade_in_active()) {
1537 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1539 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1542 items.push_back (SeparatorElem());
1543 fill_xfade_menu (items, true);
1545 xfade_in_context_menu.popup (button, time);
1548 /** Pop up a context menu for when the user clicks on an end crossfade */
1550 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1552 using namespace Menu_Helpers;
1553 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1558 MenuList& items (xfade_out_context_menu.items());
1561 if (arv->audio_region()->fade_out_active()) {
1562 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1564 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1567 items.push_back (SeparatorElem());
1568 fill_xfade_menu (items, false);
1570 xfade_out_context_menu.popup (button, time);
1574 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1576 using namespace Menu_Helpers;
1577 Menu* (Editor::*build_menu_function)();
1580 switch (item_type) {
1582 case RegionViewName:
1583 case RegionViewNameHighlight:
1584 case LeftFrameHandle:
1585 case RightFrameHandle:
1586 if (with_selection) {
1587 build_menu_function = &Editor::build_track_selection_context_menu;
1589 build_menu_function = &Editor::build_track_region_context_menu;
1594 if (with_selection) {
1595 build_menu_function = &Editor::build_track_selection_context_menu;
1597 build_menu_function = &Editor::build_track_context_menu;
1602 if (clicked_routeview->track()) {
1603 build_menu_function = &Editor::build_track_context_menu;
1605 build_menu_function = &Editor::build_track_bus_context_menu;
1610 /* probably shouldn't happen but if it does, we don't care */
1614 menu = (this->*build_menu_function)();
1615 menu->set_name ("ArdourContextMenu");
1617 /* now handle specific situations */
1619 switch (item_type) {
1621 case RegionViewName:
1622 case RegionViewNameHighlight:
1623 case LeftFrameHandle:
1624 case RightFrameHandle:
1625 if (!with_selection) {
1626 if (region_edit_menu_split_item) {
1627 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1628 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1630 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1633 if (region_edit_menu_split_multichannel_item) {
1634 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1635 region_edit_menu_split_multichannel_item->set_sensitive (true);
1637 region_edit_menu_split_multichannel_item->set_sensitive (false);
1650 /* probably shouldn't happen but if it does, we don't care */
1654 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1656 /* Bounce to disk */
1658 using namespace Menu_Helpers;
1659 MenuList& edit_items = menu->items();
1661 edit_items.push_back (SeparatorElem());
1663 switch (clicked_routeview->audio_track()->freeze_state()) {
1664 case AudioTrack::NoFreeze:
1665 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1668 case AudioTrack::Frozen:
1669 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1672 case AudioTrack::UnFrozen:
1673 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1679 if (item_type == StreamItem && clicked_routeview) {
1680 clicked_routeview->build_underlay_menu(menu);
1683 /* When the region menu is opened, we setup the actions so that they look right
1686 sensitize_the_right_region_actions ();
1687 _last_region_menu_was_main = false;
1689 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1690 menu->popup (button, time);
1694 Editor::build_track_context_menu ()
1696 using namespace Menu_Helpers;
1698 MenuList& edit_items = track_context_menu.items();
1701 add_dstream_context_items (edit_items);
1702 return &track_context_menu;
1706 Editor::build_track_bus_context_menu ()
1708 using namespace Menu_Helpers;
1710 MenuList& edit_items = track_context_menu.items();
1713 add_bus_context_items (edit_items);
1714 return &track_context_menu;
1718 Editor::build_track_region_context_menu ()
1720 using namespace Menu_Helpers;
1721 MenuList& edit_items = track_region_context_menu.items();
1724 /* we've just cleared the track region context menu, so the menu that these
1725 two items were on will have disappeared; stop them dangling.
1727 region_edit_menu_split_item = 0;
1728 region_edit_menu_split_multichannel_item = 0;
1730 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1733 boost::shared_ptr<Track> tr;
1734 boost::shared_ptr<Playlist> pl;
1736 if ((tr = rtv->track())) {
1737 add_region_context_items (edit_items, tr);
1741 add_dstream_context_items (edit_items);
1743 return &track_region_context_menu;
1747 Editor::loudness_analyze_region_selection ()
1752 Selection& s (PublicEditor::instance ().get_selection ());
1753 RegionSelection ars = s.regions;
1754 ARDOUR::AnalysisGraph ag (_session);
1755 framecnt_t total_work = 0;
1757 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1758 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1762 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1765 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1766 total_work += arv->region ()->length ();
1769 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1771 ag.set_total_frames (total_work);
1772 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1775 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1776 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1780 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1784 ag.analyze_region (ar);
1787 if (!ag.canceled ()) {
1788 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1794 Editor::loudness_analyze_range_selection ()
1799 Selection& s (PublicEditor::instance ().get_selection ());
1800 TimeSelection ts = s.time;
1801 ARDOUR::AnalysisGraph ag (_session);
1802 framecnt_t total_work = 0;
1804 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1805 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1809 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1813 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1814 total_work += j->length ();
1818 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1820 ag.set_total_frames (total_work);
1821 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1824 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1825 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1829 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1833 ag.analyze_range (rui->route (), pl, ts);
1836 if (!ag.canceled ()) {
1837 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1843 Editor::spectral_analyze_region_selection ()
1845 if (analysis_window == 0) {
1846 analysis_window = new AnalysisWindow();
1849 analysis_window->set_session(_session);
1851 analysis_window->show_all();
1854 analysis_window->set_regionmode();
1855 analysis_window->analyze();
1857 analysis_window->present();
1861 Editor::spectral_analyze_range_selection()
1863 if (analysis_window == 0) {
1864 analysis_window = new AnalysisWindow();
1867 analysis_window->set_session(_session);
1869 analysis_window->show_all();
1872 analysis_window->set_rangemode();
1873 analysis_window->analyze();
1875 analysis_window->present();
1879 Editor::build_track_selection_context_menu ()
1881 using namespace Menu_Helpers;
1882 MenuList& edit_items = track_selection_context_menu.items();
1883 edit_items.clear ();
1885 add_selection_context_items (edit_items);
1886 // edit_items.push_back (SeparatorElem());
1887 // add_dstream_context_items (edit_items);
1889 return &track_selection_context_menu;
1893 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1895 using namespace Menu_Helpers;
1897 /* OK, stick the region submenu at the top of the list, and then add
1901 RegionSelection rs = get_regions_from_selection_and_entered ();
1903 string::size_type pos = 0;
1904 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1906 /* we have to hack up the region name because "_" has a special
1907 meaning for menu titles.
1910 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1911 menu_item_name.replace (pos, 1, "__");
1915 if (_popup_region_menu_item == 0) {
1916 _popup_region_menu_item = new MenuItem (menu_item_name);
1917 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1918 _popup_region_menu_item->show ();
1920 _popup_region_menu_item->set_label (menu_item_name);
1923 /* No latering allowed in later is higher layering model */
1924 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1925 if (act && Config->get_layer_model() == LaterHigher) {
1926 act->set_sensitive (false);
1928 act->set_sensitive (true);
1931 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1933 edit_items.push_back (*_popup_region_menu_item);
1934 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1935 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1937 edit_items.push_back (SeparatorElem());
1940 /** Add context menu items relevant to selection ranges.
1941 * @param edit_items List to add the items to.
1944 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1946 using namespace Menu_Helpers;
1948 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1949 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1951 edit_items.push_back (SeparatorElem());
1952 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1954 edit_items.push_back (SeparatorElem());
1955 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1956 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1958 edit_items.push_back (SeparatorElem());
1960 edit_items.push_back (
1962 _("Move Range Start to Previous Region Boundary"),
1963 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1967 edit_items.push_back (
1969 _("Move Range Start to Next Region Boundary"),
1970 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1974 edit_items.push_back (
1976 _("Move Range End to Previous Region Boundary"),
1977 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1981 edit_items.push_back (
1983 _("Move Range End to Next Region Boundary"),
1984 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1988 edit_items.push_back (SeparatorElem());
1989 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1990 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1992 edit_items.push_back (SeparatorElem());
1993 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1995 edit_items.push_back (SeparatorElem());
1996 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1997 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1998 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
2000 edit_items.push_back (SeparatorElem());
2001 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
2003 edit_items.push_back (SeparatorElem());
2004 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
2005 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
2007 edit_items.push_back (SeparatorElem());
2008 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
2009 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
2010 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
2011 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
2012 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
2013 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
2014 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2020 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2022 using namespace Menu_Helpers;
2026 Menu *play_menu = manage (new Menu);
2027 MenuList& play_items = play_menu->items();
2028 play_menu->set_name ("ArdourContextMenu");
2030 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2031 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2032 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2033 play_items.push_back (SeparatorElem());
2034 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2036 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2040 Menu *select_menu = manage (new Menu);
2041 MenuList& select_items = select_menu->items();
2042 select_menu->set_name ("ArdourContextMenu");
2044 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2045 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2046 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2047 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2048 select_items.push_back (SeparatorElem());
2049 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2050 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2051 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2052 select_items.push_back (SeparatorElem());
2053 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2054 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2055 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2056 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2057 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2058 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2059 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2061 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2065 Menu *cutnpaste_menu = manage (new Menu);
2066 MenuList& cutnpaste_items = cutnpaste_menu->items();
2067 cutnpaste_menu->set_name ("ArdourContextMenu");
2069 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2070 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2071 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2073 cutnpaste_items.push_back (SeparatorElem());
2075 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2076 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2078 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2080 /* Adding new material */
2082 edit_items.push_back (SeparatorElem());
2083 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2084 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2088 Menu *nudge_menu = manage (new Menu());
2089 MenuList& nudge_items = nudge_menu->items();
2090 nudge_menu->set_name ("ArdourContextMenu");
2092 edit_items.push_back (SeparatorElem());
2093 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2094 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2095 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2096 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2098 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2102 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2104 using namespace Menu_Helpers;
2108 Menu *play_menu = manage (new Menu);
2109 MenuList& play_items = play_menu->items();
2110 play_menu->set_name ("ArdourContextMenu");
2112 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2113 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2114 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2118 Menu *select_menu = manage (new Menu);
2119 MenuList& select_items = select_menu->items();
2120 select_menu->set_name ("ArdourContextMenu");
2122 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2123 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2124 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2125 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2126 select_items.push_back (SeparatorElem());
2127 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2128 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2129 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2130 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2132 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2136 Menu *cutnpaste_menu = manage (new Menu);
2137 MenuList& cutnpaste_items = cutnpaste_menu->items();
2138 cutnpaste_menu->set_name ("ArdourContextMenu");
2140 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2141 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2142 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2144 Menu *nudge_menu = manage (new Menu());
2145 MenuList& nudge_items = nudge_menu->items();
2146 nudge_menu->set_name ("ArdourContextMenu");
2148 edit_items.push_back (SeparatorElem());
2149 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2150 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2151 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2152 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2154 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2158 Editor::snap_type() const
2164 Editor::snap_musical() const
2166 switch (_snap_type) {
2167 case SnapToBeatDiv128:
2168 case SnapToBeatDiv64:
2169 case SnapToBeatDiv32:
2170 case SnapToBeatDiv28:
2171 case SnapToBeatDiv24:
2172 case SnapToBeatDiv20:
2173 case SnapToBeatDiv16:
2174 case SnapToBeatDiv14:
2175 case SnapToBeatDiv12:
2176 case SnapToBeatDiv10:
2177 case SnapToBeatDiv8:
2178 case SnapToBeatDiv7:
2179 case SnapToBeatDiv6:
2180 case SnapToBeatDiv5:
2181 case SnapToBeatDiv4:
2182 case SnapToBeatDiv3:
2183 case SnapToBeatDiv2:
2195 Editor::snap_mode() const
2201 Editor::set_snap_to (SnapType st)
2203 unsigned int snap_ind = (unsigned int)st;
2205 if (internal_editing()) {
2206 internal_snap_type = st;
2208 pre_internal_snap_type = st;
2213 if (snap_ind > snap_type_strings.size() - 1) {
2215 _snap_type = (SnapType)snap_ind;
2218 string str = snap_type_strings[snap_ind];
2220 if (str != snap_type_selector.get_text()) {
2221 snap_type_selector.set_text (str);
2226 switch (_snap_type) {
2227 case SnapToBeatDiv128:
2228 case SnapToBeatDiv64:
2229 case SnapToBeatDiv32:
2230 case SnapToBeatDiv28:
2231 case SnapToBeatDiv24:
2232 case SnapToBeatDiv20:
2233 case SnapToBeatDiv16:
2234 case SnapToBeatDiv14:
2235 case SnapToBeatDiv12:
2236 case SnapToBeatDiv10:
2237 case SnapToBeatDiv8:
2238 case SnapToBeatDiv7:
2239 case SnapToBeatDiv6:
2240 case SnapToBeatDiv5:
2241 case SnapToBeatDiv4:
2242 case SnapToBeatDiv3:
2243 case SnapToBeatDiv2: {
2244 std::vector<TempoMap::BBTPoint> grid;
2245 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
2246 compute_bbt_ruler_scale (grid, leftmost_frame, leftmost_frame + current_page_samples());
2247 update_tempo_based_rulers (grid);
2251 case SnapToRegionStart:
2252 case SnapToRegionEnd:
2253 case SnapToRegionSync:
2254 case SnapToRegionBoundary:
2255 build_region_boundary_cache ();
2263 redisplay_tempo (false);
2265 SnapChanged (); /* EMIT SIGNAL */
2269 Editor::set_snap_mode (SnapMode mode)
2271 string str = snap_mode_strings[(int)mode];
2273 if (internal_editing()) {
2274 internal_snap_mode = mode;
2276 pre_internal_snap_mode = mode;
2281 if (str != snap_mode_selector.get_text ()) {
2282 snap_mode_selector.set_text (str);
2289 Editor::set_edit_point_preference (EditPoint ep, bool force)
2291 bool changed = (_edit_point != ep);
2294 if (Profile->get_mixbus())
2295 if (ep == EditAtSelectedMarker)
2296 ep = EditAtPlayhead;
2298 string str = edit_point_strings[(int)ep];
2299 if (str != edit_point_selector.get_text ()) {
2300 edit_point_selector.set_text (str);
2303 update_all_enter_cursors();
2305 if (!force && !changed) {
2309 const char* action=NULL;
2311 switch (_edit_point) {
2312 case EditAtPlayhead:
2313 action = "edit-at-playhead";
2315 case EditAtSelectedMarker:
2316 action = "edit-at-marker";
2319 action = "edit-at-mouse";
2323 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2325 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2329 bool in_track_canvas;
2331 if (!mouse_frame (foo, in_track_canvas)) {
2332 in_track_canvas = false;
2335 reset_canvas_action_sensitivity (in_track_canvas);
2341 Editor::set_state (const XMLNode& node, int version)
2343 XMLProperty const * prop;
2345 PBD::Unwinder<bool> nsi (no_save_instant, true);
2347 Tabbable::set_state (node, version);
2349 if (_session && (prop = node.property ("playhead"))) {
2351 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2353 playhead_cursor->set_position (pos);
2355 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2356 playhead_cursor->set_position (0);
2359 playhead_cursor->set_position (0);
2362 if ((prop = node.property ("mixer-width"))) {
2363 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2366 if ((prop = node.property ("zoom-focus"))) {
2367 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2370 if ((prop = node.property ("zoom"))) {
2371 /* older versions of ardour used floating point samples_per_pixel */
2372 double f = PBD::atof (prop->value());
2373 reset_zoom (llrintf (f));
2375 reset_zoom (samples_per_pixel);
2378 if ((prop = node.property ("visible-track-count"))) {
2379 set_visible_track_count (PBD::atoi (prop->value()));
2382 if ((prop = node.property ("snap-to"))) {
2383 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2384 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2387 if ((prop = node.property ("snap-mode"))) {
2388 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2389 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2390 * snap_mode_selection_done() will only mark an already active item as active
2391 * which does not trigger set_text().
2393 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2396 if ((prop = node.property ("internal-snap-to"))) {
2397 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2400 if ((prop = node.property ("internal-snap-mode"))) {
2401 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2404 if ((prop = node.property ("pre-internal-snap-to"))) {
2405 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2408 if ((prop = node.property ("pre-internal-snap-mode"))) {
2409 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2412 if ((prop = node.property ("mouse-mode"))) {
2413 MouseMode m = str2mousemode(prop->value());
2414 set_mouse_mode (m, true);
2416 set_mouse_mode (MouseObject, true);
2419 if ((prop = node.property ("left-frame")) != 0) {
2421 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2425 reset_x_origin (pos);
2429 if ((prop = node.property ("y-origin")) != 0) {
2430 reset_y_origin (atof (prop->value ()));
2433 if ((prop = node.property ("join-object-range"))) {
2434 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2435 bool yn = string_is_affirmative (prop->value());
2437 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2438 tact->set_active (!yn);
2439 tact->set_active (yn);
2441 set_mouse_mode(mouse_mode, true);
2444 if ((prop = node.property ("edit-point"))) {
2445 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2448 if ((prop = node.property ("show-measures"))) {
2449 bool yn = string_is_affirmative (prop->value());
2450 _show_measures = yn;
2453 if ((prop = node.property ("follow-playhead"))) {
2454 bool yn = string_is_affirmative (prop->value());
2455 set_follow_playhead (yn);
2458 if ((prop = node.property ("stationary-playhead"))) {
2459 bool yn = string_is_affirmative (prop->value());
2460 set_stationary_playhead (yn);
2463 if ((prop = node.property ("region-list-sort-type"))) {
2464 RegionListSortType st;
2465 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2468 if ((prop = node.property ("show-editor-mixer"))) {
2470 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2473 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2474 bool yn = string_is_affirmative (prop->value());
2476 /* do it twice to force the change */
2478 tact->set_active (!yn);
2479 tact->set_active (yn);
2482 if ((prop = node.property ("show-editor-list"))) {
2484 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2487 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2488 bool yn = string_is_affirmative (prop->value());
2490 /* do it twice to force the change */
2492 tact->set_active (!yn);
2493 tact->set_active (yn);
2496 if ((prop = node.property (X_("editor-list-page")))) {
2497 _the_notebook.set_current_page (atoi (prop->value ()));
2500 if ((prop = node.property (X_("show-marker-lines")))) {
2501 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2503 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2504 bool yn = string_is_affirmative (prop->value ());
2506 tact->set_active (!yn);
2507 tact->set_active (yn);
2510 XMLNodeList children = node.children ();
2511 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2512 selection->set_state (**i, Stateful::current_state_version);
2513 _regions->set_state (**i);
2516 if ((prop = node.property ("maximised"))) {
2517 bool yn = string_is_affirmative (prop->value());
2518 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2520 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2521 bool fs = tact && tact->get_active();
2523 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2527 if ((prop = node.property ("nudge-clock-value"))) {
2529 sscanf (prop->value().c_str(), "%" PRId64, &f);
2530 nudge_clock->set (f);
2532 nudge_clock->set_mode (AudioClock::Timecode);
2533 nudge_clock->set (_session->frame_rate() * 5, true);
2538 * Not all properties may have been in XML, but
2539 * those that are linked to a private variable may need changing
2544 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2546 yn = _show_measures;
2547 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2548 /* do it twice to force the change */
2549 tact->set_active (!yn);
2550 tact->set_active (yn);
2553 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2554 yn = _follow_playhead;
2556 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2557 if (tact->get_active() != yn) {
2558 tact->set_active (yn);
2562 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2563 yn = _stationary_playhead;
2565 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2566 if (tact->get_active() != yn) {
2567 tact->set_active (yn);
2572 return LuaInstance::instance()->set_state(node);
2576 Editor::get_state ()
2578 XMLNode* node = new XMLNode (X_("Editor"));
2581 id().print (buf, sizeof (buf));
2582 node->add_property ("id", buf);
2584 node->add_child_nocopy (Tabbable::get_state());
2586 snprintf(buf,sizeof(buf), "%f", edit_pane.get_divider ());
2587 node->add_property("edit-horizontal-pane-pos", string(buf));
2588 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2589 snprintf(buf,sizeof(buf), "%f", editor_summary_pane.get_divider());
2590 node->add_property("edit-vertical-pane-pos", string(buf));
2592 maybe_add_mixer_strip_width (*node);
2594 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2596 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2597 node->add_property ("zoom", buf);
2598 node->add_property ("snap-to", enum_2_string (_snap_type));
2599 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2600 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2601 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2602 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2603 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2604 node->add_property ("edit-point", enum_2_string (_edit_point));
2605 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2606 node->add_property ("visible-track-count", buf);
2608 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2609 node->add_property ("playhead", buf);
2610 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2611 node->add_property ("left-frame", buf);
2612 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2613 node->add_property ("y-origin", buf);
2615 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2616 node->add_property ("maximised", _maximised ? "yes" : "no");
2617 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2618 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2619 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2620 node->add_property ("mouse-mode", enum2str(mouse_mode));
2621 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2623 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2625 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2626 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2629 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2631 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2632 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2635 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2636 node->add_property (X_("editor-list-page"), buf);
2638 if (button_bindings) {
2639 XMLNode* bb = new XMLNode (X_("Buttons"));
2640 button_bindings->save (*bb);
2641 node->add_child_nocopy (*bb);
2644 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2646 node->add_child_nocopy (selection->get_state ());
2647 node->add_child_nocopy (_regions->get_state ());
2649 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2650 node->add_property ("nudge-clock-value", buf);
2652 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2653 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2658 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2659 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2661 * @return pair: TimeAxisView that y is over, layer index.
2663 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2664 * in stacked or expanded region display mode, otherwise 0.
2666 std::pair<TimeAxisView *, double>
2667 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2669 if (!trackview_relative_offset) {
2670 y -= _trackview_group->canvas_origin().y;
2674 return std::make_pair ( (TimeAxisView *) 0, 0);
2677 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2679 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2686 return std::make_pair ( (TimeAxisView *) 0, 0);
2689 /** Snap a position to the grid, if appropriate, taking into account current
2690 * grid settings and also the state of any snap modifier keys that may be pressed.
2691 * @param start Position to snap.
2692 * @param event Event to get current key modifier information from, or 0.
2695 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2697 if (!_session || !event) {
2701 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2702 if (_snap_mode == SnapOff) {
2703 snap_to_internal (start, direction, for_mark);
2706 if (_snap_mode != SnapOff) {
2707 snap_to_internal (start, direction, for_mark);
2708 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2709 /* SnapOff, but we pressed the snap_delta modifier */
2710 snap_to_internal (start, direction, for_mark);
2716 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2718 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2722 snap_to_internal (start, direction, for_mark, ensure_snap);
2726 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2728 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2729 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2731 switch (_snap_type) {
2732 case SnapToTimecodeFrame:
2733 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2734 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2735 /* start is already on a whole timecode frame, do nothing */
2736 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2737 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2739 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2743 case SnapToTimecodeSeconds:
2744 if (_session->config.get_timecode_offset_negative()) {
2745 start += _session->config.get_timecode_offset ();
2747 start -= _session->config.get_timecode_offset ();
2749 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2750 (start % one_timecode_second == 0)) {
2751 /* start is already on a whole second, do nothing */
2752 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2753 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2755 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2758 if (_session->config.get_timecode_offset_negative()) {
2759 start -= _session->config.get_timecode_offset ();
2761 start += _session->config.get_timecode_offset ();
2765 case SnapToTimecodeMinutes:
2766 if (_session->config.get_timecode_offset_negative()) {
2767 start += _session->config.get_timecode_offset ();
2769 start -= _session->config.get_timecode_offset ();
2771 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2772 (start % one_timecode_minute == 0)) {
2773 /* start is already on a whole minute, do nothing */
2774 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2775 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2777 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2779 if (_session->config.get_timecode_offset_negative()) {
2780 start -= _session->config.get_timecode_offset ();
2782 start += _session->config.get_timecode_offset ();
2786 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2787 abort(); /*NOTREACHED*/
2792 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2794 const framepos_t one_second = _session->frame_rate();
2795 const framepos_t one_minute = _session->frame_rate() * 60;
2796 framepos_t presnap = start;
2800 switch (_snap_type) {
2801 case SnapToTimecodeFrame:
2802 case SnapToTimecodeSeconds:
2803 case SnapToTimecodeMinutes:
2804 return timecode_snap_to_internal (start, direction, for_mark);
2807 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2808 start % (one_second/75) == 0) {
2809 /* start is already on a whole CD frame, do nothing */
2810 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2811 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2813 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2818 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2819 start % one_second == 0) {
2820 /* start is already on a whole second, do nothing */
2821 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2822 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2824 start = (framepos_t) floor ((double) start / one_second) * one_second;
2829 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2830 start % one_minute == 0) {
2831 /* start is already on a whole minute, do nothing */
2832 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2833 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2835 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2840 start = _session->tempo_map().round_to_bar (start, direction);
2844 start = _session->tempo_map().round_to_beat (start, direction);
2847 case SnapToBeatDiv128:
2848 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2850 case SnapToBeatDiv64:
2851 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2853 case SnapToBeatDiv32:
2854 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2856 case SnapToBeatDiv28:
2857 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2859 case SnapToBeatDiv24:
2860 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2862 case SnapToBeatDiv20:
2863 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2865 case SnapToBeatDiv16:
2866 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2868 case SnapToBeatDiv14:
2869 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2871 case SnapToBeatDiv12:
2872 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2874 case SnapToBeatDiv10:
2875 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2877 case SnapToBeatDiv8:
2878 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2880 case SnapToBeatDiv7:
2881 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2883 case SnapToBeatDiv6:
2884 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2886 case SnapToBeatDiv5:
2887 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2889 case SnapToBeatDiv4:
2890 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2892 case SnapToBeatDiv3:
2893 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2895 case SnapToBeatDiv2:
2896 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2904 _session->locations()->marks_either_side (start, before, after);
2906 if (before == max_framepos && after == max_framepos) {
2907 /* No marks to snap to, so just don't snap */
2909 } else if (before == max_framepos) {
2911 } else if (after == max_framepos) {
2913 } else if (before != max_framepos && after != max_framepos) {
2914 /* have before and after */
2915 if ((start - before) < (after - start)) {
2924 case SnapToRegionStart:
2925 case SnapToRegionEnd:
2926 case SnapToRegionSync:
2927 case SnapToRegionBoundary:
2928 if (!region_boundary_cache.empty()) {
2930 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2931 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2933 if (direction > 0) {
2934 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2936 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2939 if (next != region_boundary_cache.begin ()) {
2944 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2945 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2947 if (start > (p + n) / 2) {
2956 switch (_snap_mode) {
2966 if (presnap > start) {
2967 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2971 } else if (presnap < start) {
2972 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2978 /* handled at entry */
2986 Editor::setup_toolbar ()
2988 HBox* mode_box = manage(new HBox);
2989 mode_box->set_border_width (2);
2990 mode_box->set_spacing(2);
2992 HBox* mouse_mode_box = manage (new HBox);
2993 HBox* mouse_mode_hbox = manage (new HBox);
2994 VBox* mouse_mode_vbox = manage (new VBox);
2995 Alignment* mouse_mode_align = manage (new Alignment);
2997 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2998 mouse_mode_size_group->add_widget (smart_mode_button);
2999 mouse_mode_size_group->add_widget (mouse_move_button);
3000 mouse_mode_size_group->add_widget (mouse_cut_button);
3001 mouse_mode_size_group->add_widget (mouse_select_button);
3002 mouse_mode_size_group->add_widget (mouse_timefx_button);
3003 mouse_mode_size_group->add_widget (mouse_audition_button);
3004 mouse_mode_size_group->add_widget (mouse_draw_button);
3005 mouse_mode_size_group->add_widget (mouse_content_button);
3007 mouse_mode_size_group->add_widget (zoom_in_button);
3008 mouse_mode_size_group->add_widget (zoom_out_button);
3009 mouse_mode_size_group->add_widget (zoom_preset_selector);
3010 mouse_mode_size_group->add_widget (zoom_out_full_button);
3011 mouse_mode_size_group->add_widget (zoom_focus_selector);
3013 mouse_mode_size_group->add_widget (tav_shrink_button);
3014 mouse_mode_size_group->add_widget (tav_expand_button);
3015 mouse_mode_size_group->add_widget (visible_tracks_selector);
3017 mouse_mode_size_group->add_widget (snap_type_selector);
3018 mouse_mode_size_group->add_widget (snap_mode_selector);
3020 mouse_mode_size_group->add_widget (edit_point_selector);
3021 mouse_mode_size_group->add_widget (edit_mode_selector);
3023 mouse_mode_size_group->add_widget (*nudge_clock);
3024 mouse_mode_size_group->add_widget (nudge_forward_button);
3025 mouse_mode_size_group->add_widget (nudge_backward_button);
3027 mouse_mode_hbox->set_spacing (2);
3029 if (!ARDOUR::Profile->get_trx()) {
3030 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3033 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3034 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3036 if (!ARDOUR::Profile->get_mixbus()) {
3037 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3040 if (!ARDOUR::Profile->get_trx()) {
3041 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3042 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3043 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3044 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3047 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3049 mouse_mode_align->add (*mouse_mode_vbox);
3050 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3052 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3054 edit_mode_selector.set_name ("mouse mode button");
3056 if (!ARDOUR::Profile->get_trx()) {
3057 mode_box->pack_start (edit_mode_selector, false, false);
3060 mode_box->pack_start (*mouse_mode_box, false, false);
3064 _zoom_box.set_spacing (2);
3065 _zoom_box.set_border_width (2);
3069 zoom_preset_selector.set_name ("zoom button");
3070 zoom_preset_selector.set_image(::get_icon ("time_exp"));
3071 zoom_preset_selector.set_size_request (42, -1);
3073 zoom_in_button.set_name ("zoom button");
3074 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3075 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3076 zoom_in_button.set_related_action (act);
3078 zoom_out_button.set_name ("zoom button");
3079 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3080 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3081 zoom_out_button.set_related_action (act);
3083 zoom_out_full_button.set_name ("zoom button");
3084 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3085 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3086 zoom_out_full_button.set_related_action (act);
3088 zoom_focus_selector.set_name ("zoom button");
3090 if (ARDOUR::Profile->get_mixbus()) {
3091 _zoom_box.pack_start (zoom_preset_selector, false, false);
3092 } else if (ARDOUR::Profile->get_trx()) {
3093 mode_box->pack_start (zoom_out_button, false, false);
3094 mode_box->pack_start (zoom_in_button, false, false);
3096 _zoom_box.pack_start (zoom_out_button, false, false);
3097 _zoom_box.pack_start (zoom_in_button, false, false);
3098 _zoom_box.pack_start (zoom_out_full_button, false, false);
3099 _zoom_box.pack_start (zoom_focus_selector, false, false);
3102 /* Track zoom buttons */
3103 visible_tracks_selector.set_name ("zoom button");
3104 if (Profile->get_mixbus()) {
3105 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3106 visible_tracks_selector.set_size_request (42, -1);
3108 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3111 tav_expand_button.set_name ("zoom button");
3112 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3113 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3114 tav_expand_button.set_related_action (act);
3116 tav_shrink_button.set_name ("zoom button");
3117 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3118 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3119 tav_shrink_button.set_related_action (act);
3121 if (ARDOUR::Profile->get_mixbus()) {
3122 _zoom_box.pack_start (visible_tracks_selector);
3123 } else if (ARDOUR::Profile->get_trx()) {
3124 _zoom_box.pack_start (tav_shrink_button);
3125 _zoom_box.pack_start (tav_expand_button);
3127 _zoom_box.pack_start (visible_tracks_selector);
3128 _zoom_box.pack_start (tav_shrink_button);
3129 _zoom_box.pack_start (tav_expand_button);
3132 snap_box.set_spacing (2);
3133 snap_box.set_border_width (2);
3135 snap_type_selector.set_name ("mouse mode button");
3137 snap_mode_selector.set_name ("mouse mode button");
3139 edit_point_selector.set_name ("mouse mode button");
3141 snap_box.pack_start (snap_mode_selector, false, false);
3142 snap_box.pack_start (snap_type_selector, false, false);
3143 snap_box.pack_start (edit_point_selector, false, false);
3147 HBox *nudge_box = manage (new HBox);
3148 nudge_box->set_spacing (2);
3149 nudge_box->set_border_width (2);
3151 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3152 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3154 nudge_box->pack_start (nudge_backward_button, false, false);
3155 nudge_box->pack_start (nudge_forward_button, false, false);
3156 nudge_box->pack_start (*nudge_clock, false, false);
3159 /* Pack everything in... */
3161 HBox* hbox = manage (new HBox);
3162 hbox->set_spacing(2);
3164 toolbar_hbox.set_spacing (2);
3165 toolbar_hbox.set_border_width (1);
3167 toolbar_hbox.pack_start (*mode_box, false, false);
3168 if (!ARDOUR::Profile->get_trx()) {
3169 toolbar_hbox.pack_start (_zoom_box, false, false);
3170 toolbar_hbox.pack_start (*hbox, false, false);
3173 if (!ARDOUR::Profile->get_trx()) {
3174 hbox->pack_start (snap_box, false, false);
3175 hbox->pack_start (*nudge_box, false, false);
3180 toolbar_base.set_name ("ToolBarBase");
3181 toolbar_base.add (toolbar_hbox);
3183 _toolbar_viewport.add (toolbar_base);
3184 /* stick to the required height but allow width to vary if there's not enough room */
3185 _toolbar_viewport.set_size_request (1, -1);
3187 toolbar_frame.set_shadow_type (SHADOW_OUT);
3188 toolbar_frame.set_name ("BaseFrame");
3189 toolbar_frame.add (_toolbar_viewport);
3193 Editor::build_edit_point_menu ()
3195 using namespace Menu_Helpers;
3197 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3198 if(!Profile->get_mixbus())
3199 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3200 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3202 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3206 Editor::build_edit_mode_menu ()
3208 using namespace Menu_Helpers;
3210 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3211 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3212 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3213 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3215 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3219 Editor::build_snap_mode_menu ()
3221 using namespace Menu_Helpers;
3223 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3224 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3225 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3227 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3231 Editor::build_snap_type_menu ()
3233 using namespace Menu_Helpers;
3235 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3236 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3237 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3238 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3239 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3240 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3241 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3242 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3243 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3244 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3245 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3246 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3247 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3248 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3249 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3250 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3251 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3252 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3253 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3254 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3255 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3256 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3257 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3258 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3259 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3260 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3261 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3262 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3263 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3264 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3266 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3271 Editor::setup_tooltips ()
3273 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3274 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3275 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3276 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3277 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3278 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3279 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3280 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3281 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3282 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3283 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3284 set_tooltip (zoom_in_button, _("Zoom In"));
3285 set_tooltip (zoom_out_button, _("Zoom Out"));
3286 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3287 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3288 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3289 set_tooltip (tav_expand_button, _("Expand Tracks"));
3290 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3291 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3292 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3293 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3294 set_tooltip (edit_point_selector, _("Edit Point"));
3295 set_tooltip (edit_mode_selector, _("Edit Mode"));
3296 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3300 Editor::convert_drop_to_paths (
3301 vector<string>& paths,
3302 const RefPtr<Gdk::DragContext>& /*context*/,
3305 const SelectionData& data,
3309 if (_session == 0) {
3313 vector<string> uris = data.get_uris();
3317 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3318 are actually URI lists. So do it by hand.
3321 if (data.get_target() != "text/plain") {
3325 /* Parse the "uri-list" format that Nautilus provides,
3326 where each pathname is delimited by \r\n.
3328 THERE MAY BE NO NULL TERMINATING CHAR!!!
3331 string txt = data.get_text();
3335 p = (char *) malloc (txt.length() + 1);
3336 txt.copy (p, txt.length(), 0);
3337 p[txt.length()] = '\0';
3343 while (g_ascii_isspace (*p))
3347 while (*q && (*q != '\n') && (*q != '\r')) {
3354 while (q > p && g_ascii_isspace (*q))
3359 uris.push_back (string (p, q - p + 1));
3363 p = strchr (p, '\n');
3375 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3376 if ((*i).substr (0,7) == "file://") {
3377 paths.push_back (Glib::filename_from_uri (*i));
3385 Editor::new_tempo_section ()
3390 Editor::map_transport_state ()
3392 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3394 if (_session && _session->transport_stopped()) {
3395 have_pending_keyboard_selection = false;
3398 update_loop_range_view ();
3404 Editor::begin_selection_op_history ()
3406 selection_op_cmd_depth = 0;
3407 selection_op_history_it = 0;
3409 while(!selection_op_history.empty()) {
3410 delete selection_op_history.front();
3411 selection_op_history.pop_front();
3414 selection_undo_action->set_sensitive (false);
3415 selection_redo_action->set_sensitive (false);
3416 selection_op_history.push_front (&_selection_memento->get_state ());
3420 Editor::begin_reversible_selection_op (string name)
3423 //cerr << name << endl;
3424 /* begin/commit pairs can be nested */
3425 selection_op_cmd_depth++;
3430 Editor::commit_reversible_selection_op ()
3433 if (selection_op_cmd_depth == 1) {
3435 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3437 The user has undone some selection ops and then made a new one,
3438 making anything earlier in the list invalid.
3441 list<XMLNode *>::iterator it = selection_op_history.begin();
3442 list<XMLNode *>::iterator e_it = it;
3443 advance (e_it, selection_op_history_it);
3445 for ( ; it != e_it; ++it) {
3448 selection_op_history.erase (selection_op_history.begin(), e_it);
3451 selection_op_history.push_front (&_selection_memento->get_state ());
3452 selection_op_history_it = 0;
3454 selection_undo_action->set_sensitive (true);
3455 selection_redo_action->set_sensitive (false);
3458 if (selection_op_cmd_depth > 0) {
3459 selection_op_cmd_depth--;
3465 Editor::undo_selection_op ()
3468 selection_op_history_it++;
3470 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3471 if (n == selection_op_history_it) {
3472 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3473 selection_redo_action->set_sensitive (true);
3477 /* is there an earlier entry? */
3478 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3479 selection_undo_action->set_sensitive (false);
3485 Editor::redo_selection_op ()
3488 if (selection_op_history_it > 0) {
3489 selection_op_history_it--;
3492 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3493 if (n == selection_op_history_it) {
3494 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3495 selection_undo_action->set_sensitive (true);
3500 if (selection_op_history_it == 0) {
3501 selection_redo_action->set_sensitive (false);
3507 Editor::begin_reversible_command (string name)
3510 before.push_back (&_selection_memento->get_state ());
3511 _session->begin_reversible_command (name);
3516 Editor::begin_reversible_command (GQuark q)
3519 before.push_back (&_selection_memento->get_state ());
3520 _session->begin_reversible_command (q);
3525 Editor::abort_reversible_command ()
3528 while(!before.empty()) {
3529 delete before.front();
3532 _session->abort_reversible_command ();
3537 Editor::commit_reversible_command ()
3540 if (before.size() == 1) {
3541 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3542 redo_action->set_sensitive(false);
3543 undo_action->set_sensitive(true);
3544 begin_selection_op_history ();
3547 if (before.empty()) {
3548 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3553 _session->commit_reversible_command ();
3558 Editor::history_changed ()
3562 if (undo_action && _session) {
3563 if (_session->undo_depth() == 0) {
3564 label = S_("Command|Undo");
3566 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3568 undo_action->property_label() = label;
3571 if (redo_action && _session) {
3572 if (_session->redo_depth() == 0) {
3574 redo_action->set_sensitive (false);
3576 label = string_compose(_("Redo (%1)"), _session->next_redo());
3577 redo_action->set_sensitive (true);
3579 redo_action->property_label() = label;
3584 Editor::duplicate_range (bool with_dialog)
3588 RegionSelection rs = get_regions_from_selection_and_entered ();
3590 if ( selection->time.length() == 0 && rs.empty()) {
3596 ArdourDialog win (_("Duplicate"));
3597 Label label (_("Number of duplications:"));
3598 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3599 SpinButton spinner (adjustment, 0.0, 1);
3602 win.get_vbox()->set_spacing (12);
3603 win.get_vbox()->pack_start (hbox);
3604 hbox.set_border_width (6);
3605 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3607 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3608 place, visually. so do this by hand.
3611 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3612 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3613 spinner.grab_focus();
3619 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3620 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3621 win.set_default_response (RESPONSE_ACCEPT);
3623 spinner.grab_focus ();
3625 switch (win.run ()) {
3626 case RESPONSE_ACCEPT:
3632 times = adjustment.get_value();
3635 if ((current_mouse_mode() == Editing::MouseRange)) {
3636 if (selection->time.length()) {
3637 duplicate_selection (times);
3639 } else if (get_smart_mode()) {
3640 if (selection->time.length()) {
3641 duplicate_selection (times);
3643 duplicate_some_regions (rs, times);
3645 duplicate_some_regions (rs, times);
3650 Editor::set_edit_mode (EditMode m)
3652 Config->set_edit_mode (m);
3656 Editor::cycle_edit_mode ()
3658 switch (Config->get_edit_mode()) {
3660 Config->set_edit_mode (Ripple);
3664 Config->set_edit_mode (Lock);
3667 Config->set_edit_mode (Slide);
3673 Editor::edit_mode_selection_done ( EditMode m )
3675 Config->set_edit_mode ( m );
3679 Editor::snap_type_selection_done (SnapType snaptype)
3681 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3683 ract->set_active ();
3688 Editor::snap_mode_selection_done (SnapMode mode)
3690 RefPtr<RadioAction> ract = snap_mode_action (mode);
3693 ract->set_active (true);
3698 Editor::cycle_edit_point (bool with_marker)
3700 if(Profile->get_mixbus())
3701 with_marker = false;
3703 switch (_edit_point) {
3705 set_edit_point_preference (EditAtPlayhead);
3707 case EditAtPlayhead:
3709 set_edit_point_preference (EditAtSelectedMarker);
3711 set_edit_point_preference (EditAtMouse);
3714 case EditAtSelectedMarker:
3715 set_edit_point_preference (EditAtMouse);
3721 Editor::edit_point_selection_done (EditPoint ep)
3723 set_edit_point_preference ( ep );
3727 Editor::build_zoom_focus_menu ()
3729 using namespace Menu_Helpers;
3731 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3732 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3733 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3734 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3735 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3736 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3738 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3742 Editor::zoom_focus_selection_done ( ZoomFocus f )
3744 RefPtr<RadioAction> ract = zoom_focus_action (f);
3746 ract->set_active ();
3751 Editor::build_track_count_menu ()
3753 using namespace Menu_Helpers;
3755 if (!Profile->get_mixbus()) {
3756 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3757 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3758 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3759 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3760 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3761 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3762 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3763 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3764 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3765 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3766 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3767 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3768 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3770 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3771 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3772 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3773 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3774 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3775 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3776 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3777 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3778 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3779 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3781 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3782 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3783 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3784 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3785 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3786 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3787 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3788 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3789 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3790 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3791 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3796 Editor::set_zoom_preset (int64_t ms)
3799 temporal_zoom_session();
3803 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3804 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3808 Editor::set_visible_track_count (int32_t n)
3810 _visible_track_count = n;
3812 /* if the canvas hasn't really been allocated any size yet, just
3813 record the desired number of visible tracks and return. when canvas
3814 allocation happens, we will get called again and then we can do the
3818 if (_visible_canvas_height <= 1) {
3824 DisplaySuspender ds;
3826 if (_visible_track_count > 0) {
3827 h = trackviews_height() / _visible_track_count;
3828 std::ostringstream s;
3829 s << _visible_track_count;
3831 } else if (_visible_track_count == 0) {
3833 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3834 if ((*i)->marked_for_display()) {
3838 h = trackviews_height() / n;
3841 /* negative value means that the visible track count has
3842 been overridden by explicit track height changes.
3844 visible_tracks_selector.set_text (X_("*"));
3848 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3849 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3852 if (str != visible_tracks_selector.get_text()) {
3853 visible_tracks_selector.set_text (str);
3858 Editor::override_visible_track_count ()
3860 _visible_track_count = -1;
3861 visible_tracks_selector.set_text ( _("*") );
3865 Editor::edit_controls_button_release (GdkEventButton* ev)
3867 if (Keyboard::is_context_menu_event (ev)) {
3868 ARDOUR_UI::instance()->add_route ();
3869 } else if (ev->button == 1) {
3870 selection->clear_tracks ();
3877 Editor::mouse_select_button_release (GdkEventButton* ev)
3879 /* this handles just right-clicks */
3881 if (ev->button != 3) {
3889 Editor::set_zoom_focus (ZoomFocus f)
3891 string str = zoom_focus_strings[(int)f];
3893 if (str != zoom_focus_selector.get_text()) {
3894 zoom_focus_selector.set_text (str);
3897 if (zoom_focus != f) {
3904 Editor::cycle_zoom_focus ()
3906 switch (zoom_focus) {
3908 set_zoom_focus (ZoomFocusRight);
3910 case ZoomFocusRight:
3911 set_zoom_focus (ZoomFocusCenter);
3913 case ZoomFocusCenter:
3914 set_zoom_focus (ZoomFocusPlayhead);
3916 case ZoomFocusPlayhead:
3917 set_zoom_focus (ZoomFocusMouse);
3919 case ZoomFocusMouse:
3920 set_zoom_focus (ZoomFocusEdit);
3923 set_zoom_focus (ZoomFocusLeft);
3929 Editor::set_show_measures (bool yn)
3931 if (_show_measures != yn) {
3934 if ((_show_measures = yn) == true) {
3936 tempo_lines->show();
3939 std::vector<TempoMap::BBTPoint> grid;
3940 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3941 draw_measures (grid);
3949 Editor::toggle_follow_playhead ()
3951 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3953 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3954 set_follow_playhead (tact->get_active());
3958 /** @param yn true to follow playhead, otherwise false.
3959 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3962 Editor::set_follow_playhead (bool yn, bool catch_up)
3964 if (_follow_playhead != yn) {
3965 if ((_follow_playhead = yn) == true && catch_up) {
3967 reset_x_origin_to_follow_playhead ();
3974 Editor::toggle_stationary_playhead ()
3976 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3978 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3979 set_stationary_playhead (tact->get_active());
3984 Editor::set_stationary_playhead (bool yn)
3986 if (_stationary_playhead != yn) {
3987 if ((_stationary_playhead = yn) == true) {
3989 // FIXME need a 3.0 equivalent of this 2.X call
3990 // update_current_screen ();
3997 Editor::playlist_selector () const
3999 return *_playlist_selector;
4003 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4005 if (paste_count == 0) {
4006 /* don't bother calculating an offset that will be zero anyway */
4010 /* calculate basic unsnapped multi-paste offset */
4011 framecnt_t offset = paste_count * duration;
4013 /* snap offset so pos + offset is aligned to the grid */
4014 framepos_t offset_pos = pos + offset;
4015 snap_to(offset_pos, RoundUpMaybe);
4016 offset = offset_pos - pos;
4022 Editor::get_grid_beat_divisions(framepos_t position)
4024 switch (_snap_type) {
4025 case SnapToBeatDiv128: return 128;
4026 case SnapToBeatDiv64: return 64;
4027 case SnapToBeatDiv32: return 32;
4028 case SnapToBeatDiv28: return 28;
4029 case SnapToBeatDiv24: return 24;
4030 case SnapToBeatDiv20: return 20;
4031 case SnapToBeatDiv16: return 16;
4032 case SnapToBeatDiv14: return 14;
4033 case SnapToBeatDiv12: return 12;
4034 case SnapToBeatDiv10: return 10;
4035 case SnapToBeatDiv8: return 8;
4036 case SnapToBeatDiv7: return 7;
4037 case SnapToBeatDiv6: return 6;
4038 case SnapToBeatDiv5: return 5;
4039 case SnapToBeatDiv4: return 4;
4040 case SnapToBeatDiv3: return 3;
4041 case SnapToBeatDiv2: return 2;
4048 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4052 const unsigned divisions = get_grid_beat_divisions(position);
4054 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4057 switch (_snap_type) {
4059 return Evoral::Beats(1.0);
4062 return Evoral::Beats(_session->tempo_map().meter_at_frame (position).divisions_per_bar());
4070 return Evoral::Beats();
4074 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4078 ret = nudge_clock->current_duration (pos);
4079 next = ret + 1; /* XXXX fix me */
4085 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4087 ArdourDialog dialog (_("Playlist Deletion"));
4088 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4089 "If it is kept, its audio files will not be cleaned.\n"
4090 "If it is deleted, audio files used by it alone will be cleaned."),
4093 dialog.set_position (WIN_POS_CENTER);
4094 dialog.get_vbox()->pack_start (label);
4098 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4099 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4100 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4101 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4102 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4104 // by default gtk uses the left most button
4105 keep->grab_focus ();
4107 switch (dialog.run ()) {
4109 /* keep this and all remaining ones */
4114 /* delete this and all others */
4118 case RESPONSE_ACCEPT:
4119 /* delete the playlist */
4123 case RESPONSE_REJECT:
4124 /* keep the playlist */
4136 Editor::audio_region_selection_covers (framepos_t where)
4138 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4139 if ((*a)->region()->covers (where)) {
4148 Editor::prepare_for_cleanup ()
4150 cut_buffer->clear_regions ();
4151 cut_buffer->clear_playlists ();
4153 selection->clear_regions ();
4154 selection->clear_playlists ();
4156 _regions->suspend_redisplay ();
4160 Editor::finish_cleanup ()
4162 _regions->resume_redisplay ();
4166 Editor::transport_loop_location()
4169 return _session->locations()->auto_loop_location();
4176 Editor::transport_punch_location()
4179 return _session->locations()->auto_punch_location();
4186 Editor::control_layout_scroll (GdkEventScroll* ev)
4188 /* Just forward to the normal canvas scroll method. The coordinate
4189 systems are different but since the canvas is always larger than the
4190 track headers, and aligned with the trackview area, this will work.
4192 In the not too distant future this layout is going away anyway and
4193 headers will be on the canvas.
4195 return canvas_scroll_event (ev, false);
4199 Editor::session_state_saved (string)
4202 _snapshots->redisplay ();
4206 Editor::maximise_editing_space ()
4212 Gtk::Window* toplevel = current_toplevel();
4215 toplevel->fullscreen ();
4221 Editor::restore_editing_space ()
4227 Gtk::Window* toplevel = current_toplevel();
4230 toplevel->unfullscreen();
4236 * Make new playlists for a given track and also any others that belong
4237 * to the same active route group with the `select' property.
4242 Editor::new_playlists (TimeAxisView* v)
4244 begin_reversible_command (_("new playlists"));
4245 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4246 _session->playlists->get (playlists);
4247 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4248 commit_reversible_command ();
4252 * Use a copy of the current playlist for a given track and also any others that belong
4253 * to the same active route group with the `select' property.
4258 Editor::copy_playlists (TimeAxisView* v)
4260 begin_reversible_command (_("copy playlists"));
4261 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4262 _session->playlists->get (playlists);
4263 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4264 commit_reversible_command ();
4267 /** Clear the current playlist for a given track and also any others that belong
4268 * to the same active route group with the `select' property.
4273 Editor::clear_playlists (TimeAxisView* v)
4275 begin_reversible_command (_("clear playlists"));
4276 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4277 _session->playlists->get (playlists);
4278 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4279 commit_reversible_command ();
4283 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4285 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4289 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4291 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4295 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4297 atv.clear_playlist ();
4301 Editor::get_y_origin () const
4303 return vertical_adjustment.get_value ();
4306 /** Queue up a change to the viewport x origin.
4307 * @param frame New x origin.
4310 Editor::reset_x_origin (framepos_t frame)
4312 pending_visual_change.add (VisualChange::TimeOrigin);
4313 pending_visual_change.time_origin = frame;
4314 ensure_visual_change_idle_handler ();
4318 Editor::reset_y_origin (double y)
4320 pending_visual_change.add (VisualChange::YOrigin);
4321 pending_visual_change.y_origin = y;
4322 ensure_visual_change_idle_handler ();
4326 Editor::reset_zoom (framecnt_t spp)
4328 if (spp == samples_per_pixel) {
4332 pending_visual_change.add (VisualChange::ZoomLevel);
4333 pending_visual_change.samples_per_pixel = spp;
4334 ensure_visual_change_idle_handler ();
4338 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4340 reset_x_origin (frame);
4343 if (!no_save_visual) {
4344 undo_visual_stack.push_back (current_visual_state(false));
4348 Editor::VisualState::VisualState (bool with_tracks)
4349 : gui_state (with_tracks ? new GUIObjectState : 0)
4353 Editor::VisualState::~VisualState ()
4358 Editor::VisualState*
4359 Editor::current_visual_state (bool with_tracks)
4361 VisualState* vs = new VisualState (with_tracks);
4362 vs->y_position = vertical_adjustment.get_value();
4363 vs->samples_per_pixel = samples_per_pixel;
4364 vs->leftmost_frame = leftmost_frame;
4365 vs->zoom_focus = zoom_focus;
4368 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4375 Editor::undo_visual_state ()
4377 if (undo_visual_stack.empty()) {
4381 VisualState* vs = undo_visual_stack.back();
4382 undo_visual_stack.pop_back();
4385 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4388 use_visual_state (*vs);
4393 Editor::redo_visual_state ()
4395 if (redo_visual_stack.empty()) {
4399 VisualState* vs = redo_visual_stack.back();
4400 redo_visual_stack.pop_back();
4402 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4403 // why do we check here?
4404 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4407 use_visual_state (*vs);
4412 Editor::swap_visual_state ()
4414 if (undo_visual_stack.empty()) {
4415 redo_visual_state ();
4417 undo_visual_state ();
4422 Editor::use_visual_state (VisualState& vs)
4424 PBD::Unwinder<bool> nsv (no_save_visual, true);
4425 DisplaySuspender ds;
4427 vertical_adjustment.set_value (vs.y_position);
4429 set_zoom_focus (vs.zoom_focus);
4430 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4433 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4435 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4436 (*i)->clear_property_cache();
4437 (*i)->reset_visual_state ();
4441 _routes->update_visibility ();
4444 /** This is the core function that controls the zoom level of the canvas. It is called
4445 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4446 * @param spp new number of samples per pixel
4449 Editor::set_samples_per_pixel (framecnt_t spp)
4455 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4456 const framecnt_t lots_of_pixels = 4000;
4458 /* if the zoom level is greater than what you'd get trying to display 3
4459 * days of audio on a really big screen, then it's too big.
4462 if (spp * lots_of_pixels > three_days) {
4466 samples_per_pixel = spp;
4469 tempo_lines->tempo_map_changed();
4472 bool const showing_time_selection = selection->time.length() > 0;
4474 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4475 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4476 (*i)->reshow_selection (selection->time);
4480 ZoomChanged (); /* EMIT_SIGNAL */
4482 ArdourCanvas::GtkCanvasViewport* c;
4484 c = get_track_canvas();
4486 c->canvas()->zoomed ();
4489 if (playhead_cursor) {
4490 playhead_cursor->set_position (playhead_cursor->current_frame ());
4493 refresh_location_display();
4494 _summary->set_overlays_dirty ();
4496 update_marker_labels ();
4502 Editor::queue_visual_videotimeline_update ()
4505 * pending_visual_change.add (VisualChange::VideoTimeline);
4506 * or maybe even more specific: which videotimeline-image
4507 * currently it calls update_video_timeline() to update
4508 * _all outdated_ images on the video-timeline.
4509 * see 'exposeimg()' in video_image_frame.cc
4511 ensure_visual_change_idle_handler ();
4515 Editor::ensure_visual_change_idle_handler ()
4517 if (pending_visual_change.idle_handler_id < 0) {
4518 // see comment in add_to_idle_resize above.
4519 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4520 pending_visual_change.being_handled = false;
4525 Editor::_idle_visual_changer (void* arg)
4527 return static_cast<Editor*>(arg)->idle_visual_changer ();
4531 Editor::idle_visual_changer ()
4533 /* set_horizontal_position() below (and maybe other calls) call
4534 gtk_main_iteration(), so it's possible that a signal will be handled
4535 half-way through this method. If this signal wants an
4536 idle_visual_changer we must schedule another one after this one, so
4537 mark the idle_handler_id as -1 here to allow that. Also make a note
4538 that we are doing the visual change, so that changes in response to
4539 super-rapid-screen-update can be dropped if we are still processing
4543 pending_visual_change.idle_handler_id = -1;
4544 pending_visual_change.being_handled = true;
4546 VisualChange vc = pending_visual_change;
4548 pending_visual_change.pending = (VisualChange::Type) 0;
4550 visual_changer (vc);
4552 pending_visual_change.being_handled = false;
4554 return 0; /* this is always a one-shot call */
4558 Editor::visual_changer (const VisualChange& vc)
4560 double const last_time_origin = horizontal_position ();
4562 if (vc.pending & VisualChange::ZoomLevel) {
4563 set_samples_per_pixel (vc.samples_per_pixel);
4565 compute_fixed_ruler_scale ();
4567 std::vector<TempoMap::BBTPoint> grid;
4568 compute_current_bbt_points (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4569 compute_bbt_ruler_scale (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4570 update_tempo_based_rulers (grid);
4572 update_video_timeline();
4575 if (vc.pending & VisualChange::TimeOrigin) {
4576 set_horizontal_position (vc.time_origin / samples_per_pixel);
4579 if (vc.pending & VisualChange::YOrigin) {
4580 vertical_adjustment.set_value (vc.y_origin);
4583 if (last_time_origin == horizontal_position ()) {
4584 /* changed signal not emitted */
4585 update_fixed_rulers ();
4586 redisplay_tempo (true);
4589 if (!(vc.pending & VisualChange::ZoomLevel)) {
4590 update_video_timeline();
4593 _summary->set_overlays_dirty ();
4596 struct EditorOrderTimeAxisSorter {
4597 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4598 return a->order () < b->order ();
4603 Editor::sort_track_selection (TrackViewList& sel)
4605 EditorOrderTimeAxisSorter cmp;
4610 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4613 framepos_t where = 0;
4614 EditPoint ep = _edit_point;
4616 if (Profile->get_mixbus())
4617 if (ep == EditAtSelectedMarker)
4618 ep = EditAtPlayhead;
4620 if (from_outside_canvas && (ep == EditAtMouse)) {
4621 ep = EditAtPlayhead;
4622 } else if (from_context_menu && (ep == EditAtMouse)) {
4623 return canvas_event_sample (&context_click_event, 0, 0);
4626 if (entered_marker) {
4627 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4628 return entered_marker->position();
4631 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4632 ep = EditAtSelectedMarker;
4635 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4636 ep = EditAtPlayhead;
4640 case EditAtPlayhead:
4641 if (_dragging_playhead) {
4642 where = *_control_scroll_target;
4644 where = _session->audible_frame();
4646 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4649 case EditAtSelectedMarker:
4650 if (!selection->markers.empty()) {
4652 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4655 where = loc->start();
4659 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4667 if (!mouse_frame (where, ignored)) {
4668 /* XXX not right but what can we do ? */
4672 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4680 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4682 if (!_session) return;
4684 begin_reversible_command (cmd);
4688 if ((tll = transport_loop_location()) == 0) {
4689 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4690 XMLNode &before = _session->locations()->get_state();
4691 _session->locations()->add (loc, true);
4692 _session->set_auto_loop_location (loc);
4693 XMLNode &after = _session->locations()->get_state();
4694 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4696 XMLNode &before = tll->get_state();
4697 tll->set_hidden (false, this);
4698 tll->set (start, end);
4699 XMLNode &after = tll->get_state();
4700 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4703 commit_reversible_command ();
4707 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4709 if (!_session) return;
4711 begin_reversible_command (cmd);
4715 if ((tpl = transport_punch_location()) == 0) {
4716 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4717 XMLNode &before = _session->locations()->get_state();
4718 _session->locations()->add (loc, true);
4719 _session->set_auto_punch_location (loc);
4720 XMLNode &after = _session->locations()->get_state();
4721 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4723 XMLNode &before = tpl->get_state();
4724 tpl->set_hidden (false, this);
4725 tpl->set (start, end);
4726 XMLNode &after = tpl->get_state();
4727 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4730 commit_reversible_command ();
4733 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4734 * @param rs List to which found regions are added.
4735 * @param where Time to look at.
4736 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4739 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4741 const TrackViewList* tracks;
4744 tracks = &track_views;
4749 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4751 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4754 boost::shared_ptr<Track> tr;
4755 boost::shared_ptr<Playlist> pl;
4757 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4759 boost::shared_ptr<RegionList> regions = pl->regions_at (
4760 (framepos_t) floor ( (double) where * tr->speed()));
4762 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4763 RegionView* rv = rtv->view()->find_view (*i);
4774 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4776 const TrackViewList* tracks;
4779 tracks = &track_views;
4784 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4785 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4787 boost::shared_ptr<Track> tr;
4788 boost::shared_ptr<Playlist> pl;
4790 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4792 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4793 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4795 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4797 RegionView* rv = rtv->view()->find_view (*i);
4808 /** Get regions using the following method:
4810 * Make a region list using:
4811 * (a) any selected regions
4812 * (b) the intersection of any selected tracks and the edit point(*)
4813 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4815 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4817 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4821 Editor::get_regions_from_selection_and_edit_point ()
4823 RegionSelection regions;
4825 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4826 regions.add (entered_regionview);
4828 regions = selection->regions;
4831 if ( regions.empty() ) {
4832 TrackViewList tracks = selection->tracks;
4834 if (!tracks.empty()) {
4835 /* no region selected or entered, but some selected tracks:
4836 * act on all regions on the selected tracks at the edit point
4838 framepos_t const where = get_preferred_edit_position ();
4839 get_regions_at(regions, where, tracks);
4846 /** Get regions using the following method:
4848 * Make a region list using:
4849 * (a) any selected regions
4850 * (b) the intersection of any selected tracks and the edit point(*)
4851 * (c) if neither exists, then whatever region is under the mouse
4853 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4855 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4858 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4860 RegionSelection regions;
4862 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4863 regions.add (entered_regionview);
4865 regions = selection->regions;
4868 if ( regions.empty() ) {
4869 TrackViewList tracks = selection->tracks;
4871 if (!tracks.empty()) {
4872 /* no region selected or entered, but some selected tracks:
4873 * act on all regions on the selected tracks at the edit point
4875 get_regions_at(regions, pos, tracks);
4882 /** Start with regions that are selected, or the entered regionview if none are selected.
4883 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4884 * of the regions that we started with.
4888 Editor::get_regions_from_selection_and_entered () const
4890 RegionSelection regions = selection->regions;
4892 if (regions.empty() && entered_regionview) {
4893 regions.add (entered_regionview);
4900 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4902 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4903 RouteTimeAxisView* rtav;
4905 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4906 boost::shared_ptr<Playlist> pl;
4907 std::vector<boost::shared_ptr<Region> > results;
4908 boost::shared_ptr<Track> tr;
4910 if ((tr = rtav->track()) == 0) {
4915 if ((pl = (tr->playlist())) != 0) {
4916 boost::shared_ptr<Region> r = pl->region_by_id (id);
4918 RegionView* rv = rtav->view()->find_view (r);
4920 regions.push_back (rv);
4929 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4932 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4933 MidiTimeAxisView* mtav;
4935 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4937 mtav->get_per_region_note_selection (selection);
4944 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4946 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4948 RouteTimeAxisView* tatv;
4950 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4952 boost::shared_ptr<Playlist> pl;
4953 vector<boost::shared_ptr<Region> > results;
4955 boost::shared_ptr<Track> tr;
4957 if ((tr = tatv->track()) == 0) {
4962 if ((pl = (tr->playlist())) != 0) {
4963 if (src_comparison) {
4964 pl->get_source_equivalent_regions (region, results);
4966 pl->get_region_list_equivalent_regions (region, results);
4970 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4971 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4972 regions.push_back (marv);
4981 Editor::show_rhythm_ferret ()
4983 if (rhythm_ferret == 0) {
4984 rhythm_ferret = new RhythmFerret(*this);
4987 rhythm_ferret->set_session (_session);
4988 rhythm_ferret->show ();
4989 rhythm_ferret->present ();
4993 Editor::first_idle ()
4995 MessageDialog* dialog = 0;
4997 if (track_views.size() > 1) {
4998 Timers::TimerSuspender t;
4999 dialog = new MessageDialog (
5000 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5004 ARDOUR_UI::instance()->flush_pending ();
5007 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5011 // first idle adds route children (automation tracks), so we need to redisplay here
5012 _routes->redisplay ();
5016 if (_session->undo_depth() == 0) {
5017 undo_action->set_sensitive(false);
5019 redo_action->set_sensitive(false);
5020 begin_selection_op_history ();
5026 Editor::_idle_resize (gpointer arg)
5028 return ((Editor*)arg)->idle_resize ();
5032 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5034 if (resize_idle_id < 0) {
5035 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5036 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5037 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5039 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5040 _pending_resize_amount = 0;
5043 /* make a note of the smallest resulting height, so that we can clamp the
5044 lower limit at TimeAxisView::hSmall */
5046 int32_t min_resulting = INT32_MAX;
5048 _pending_resize_amount += h;
5049 _pending_resize_view = view;
5051 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5053 if (selection->tracks.contains (_pending_resize_view)) {
5054 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5055 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5059 if (min_resulting < 0) {
5064 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5065 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5069 /** Handle pending resizing of tracks */
5071 Editor::idle_resize ()
5073 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5075 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5076 selection->tracks.contains (_pending_resize_view)) {
5078 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5079 if (*i != _pending_resize_view) {
5080 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5085 _pending_resize_amount = 0;
5086 _group_tabs->set_dirty ();
5087 resize_idle_id = -1;
5095 ENSURE_GUI_THREAD (*this, &Editor::located);
5098 playhead_cursor->set_position (_session->audible_frame ());
5099 if (_follow_playhead && !_pending_initial_locate) {
5100 reset_x_origin_to_follow_playhead ();
5104 _pending_locate_request = false;
5105 _pending_initial_locate = false;
5109 Editor::region_view_added (RegionView * rv)
5111 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5112 if (rv->region ()->id () == (*pr)) {
5113 selection->add (rv);
5114 selection->regions.pending.erase (pr);
5119 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5121 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5122 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5123 if (rv->region()->id () == (*rnote).first) {
5124 mrv->select_notes ((*rnote).second);
5125 selection->pending_midi_note_selection.erase(rnote);
5131 _summary->set_background_dirty ();
5135 Editor::region_view_removed ()
5137 _summary->set_background_dirty ();
5141 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5143 TrackViewList::const_iterator j = track_views.begin ();
5144 while (j != track_views.end()) {
5145 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5146 if (rtv && rtv->route() == r) {
5157 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5161 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5162 TimeAxisView* tv = axis_view_from_route (*i);
5172 Editor::suspend_route_redisplay ()
5175 _routes->suspend_redisplay();
5180 Editor::resume_route_redisplay ()
5183 _routes->redisplay(); // queue redisplay
5184 _routes->resume_redisplay();
5189 Editor::add_vcas (VCAList& vcas)
5191 VCATimeAxisView* vtv;
5192 list<VCATimeAxisView*> new_views;
5194 for (VCAList::iterator v = vcas.begin(); v != vcas.end(); ++v) {
5195 vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5197 new_views.push_back (vtv);
5200 if (new_views.size() > 0) {
5201 _routes->vcas_added (new_views);
5206 Editor::add_routes (RouteList& routes)
5208 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5210 RouteTimeAxisView *rtv;
5211 list<RouteTimeAxisView*> new_views;
5212 TrackViewList new_selection;
5213 bool from_scratch = (track_views.size() == 0);
5215 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5216 boost::shared_ptr<Route> route = (*x);
5218 if (route->is_auditioner() || route->is_monitor()) {
5222 DataType dt = route->input()->default_type();
5224 if (dt == ARDOUR::DataType::AUDIO) {
5225 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5226 rtv->set_route (route);
5227 } else if (dt == ARDOUR::DataType::MIDI) {
5228 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5229 rtv->set_route (route);
5231 throw unknown_type();
5234 new_views.push_back (rtv);
5235 track_views.push_back (rtv);
5236 new_selection.push_back (rtv);
5238 rtv->effective_gain_display ();
5240 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5241 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5244 if (new_views.size() > 0) {
5245 _routes->routes_added (new_views);
5246 _summary->routes_added (new_views);
5249 if (!from_scratch) {
5250 selection->tracks.clear();
5251 selection->add (new_selection);
5252 begin_selection_op_history();
5255 if (show_editor_mixer_when_tracks_arrive) {
5256 show_editor_mixer (true);
5259 editor_list_button.set_sensitive (true);
5263 Editor::timeaxisview_deleted (TimeAxisView *tv)
5265 if (tv == entered_track) {
5269 if (_session && _session->deletion_in_progress()) {
5270 /* the situation is under control */
5274 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5276 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5278 _routes->route_removed (tv);
5280 TimeAxisView::Children c = tv->get_child_list ();
5281 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5282 if (entered_track == i->get()) {
5287 /* remove it from the list of track views */
5289 TrackViewList::iterator i;
5291 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5292 i = track_views.erase (i);
5295 /* update whatever the current mixer strip is displaying, if revelant */
5297 boost::shared_ptr<Route> route;
5300 route = rtav->route ();
5303 if (current_mixer_strip && current_mixer_strip->route() == route) {
5305 TimeAxisView* next_tv;
5307 if (track_views.empty()) {
5309 } else if (i == track_views.end()) {
5310 next_tv = track_views.front();
5317 set_selected_mixer_strip (*next_tv);
5319 /* make the editor mixer strip go away setting the
5320 * button to inactive (which also unticks the menu option)
5323 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5329 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5331 if (apply_to_selection) {
5332 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5334 TrackSelection::iterator j = i;
5337 hide_track_in_display (*i, false);
5342 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5344 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5345 // this will hide the mixer strip
5346 set_selected_mixer_strip (*tv);
5349 _routes->hide_track_in_display (*tv);
5354 Editor::sync_track_view_list_and_routes ()
5356 track_views = TrackViewList (_routes->views ());
5358 _summary->set_background_dirty();
5359 _group_tabs->set_dirty ();
5361 return false; // do not call again (until needed)
5365 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5367 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5372 /** Find a RouteTimeAxisView by the ID of its route */
5374 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5376 RouteTimeAxisView* v;
5378 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5379 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5380 if(v->route()->id() == id) {
5390 Editor::fit_route_group (RouteGroup *g)
5392 TrackViewList ts = axis_views_from_routes (g->route_list ());
5397 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5399 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5402 _session->cancel_audition ();
5406 if (_session->is_auditioning()) {
5407 _session->cancel_audition ();
5408 if (r == last_audition_region) {
5413 _session->audition_region (r);
5414 last_audition_region = r;
5419 Editor::hide_a_region (boost::shared_ptr<Region> r)
5421 r->set_hidden (true);
5425 Editor::show_a_region (boost::shared_ptr<Region> r)
5427 r->set_hidden (false);
5431 Editor::audition_region_from_region_list ()
5433 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5437 Editor::hide_region_from_region_list ()
5439 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5443 Editor::show_region_in_region_list ()
5445 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5449 Editor::step_edit_status_change (bool yn)
5452 start_step_editing ();
5454 stop_step_editing ();
5459 Editor::start_step_editing ()
5461 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5465 Editor::stop_step_editing ()
5467 step_edit_connection.disconnect ();
5471 Editor::check_step_edit ()
5473 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5474 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5476 mtv->check_step_edit ();
5480 return true; // do it again, till we stop
5484 Editor::scroll_press (Direction dir)
5486 ++_scroll_callbacks;
5488 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5489 /* delay the first auto-repeat */
5495 scroll_backward (1);
5503 scroll_up_one_track ();
5507 scroll_down_one_track ();
5511 /* do hacky auto-repeat */
5512 if (!_scroll_connection.connected ()) {
5514 _scroll_connection = Glib::signal_timeout().connect (
5515 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5518 _scroll_callbacks = 0;
5525 Editor::scroll_release ()
5527 _scroll_connection.disconnect ();
5530 /** Queue a change for the Editor viewport x origin to follow the playhead */
5532 Editor::reset_x_origin_to_follow_playhead ()
5534 framepos_t const frame = playhead_cursor->current_frame ();
5536 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5538 if (_session->transport_speed() < 0) {
5540 if (frame > (current_page_samples() / 2)) {
5541 center_screen (frame-(current_page_samples()/2));
5543 center_screen (current_page_samples()/2);
5550 if (frame < leftmost_frame) {
5552 if (_session->transport_rolling()) {
5553 /* rolling; end up with the playhead at the right of the page */
5554 l = frame - current_page_samples ();
5556 /* not rolling: end up with the playhead 1/4 of the way along the page */
5557 l = frame - current_page_samples() / 4;
5561 if (_session->transport_rolling()) {
5562 /* rolling: end up with the playhead on the left of the page */
5565 /* not rolling: end up with the playhead 3/4 of the way along the page */
5566 l = frame - 3 * current_page_samples() / 4;
5574 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5580 Editor::super_rapid_screen_update ()
5582 if (!_session || !_session->engine().running()) {
5586 /* METERING / MIXER STRIPS */
5588 /* update track meters, if required */
5589 if (contents().is_mapped() && meters_running) {
5590 RouteTimeAxisView* rtv;
5591 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5592 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5593 rtv->fast_update ();
5598 /* and any current mixer strip */
5599 if (current_mixer_strip) {
5600 current_mixer_strip->fast_update ();
5603 /* PLAYHEAD AND VIEWPORT */
5605 framepos_t const frame = _session->audible_frame();
5607 /* There are a few reasons why we might not update the playhead / viewport stuff:
5609 * 1. we don't update things when there's a pending locate request, otherwise
5610 * when the editor requests a locate there is a chance that this method
5611 * will move the playhead before the locate request is processed, causing
5613 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5614 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5617 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5619 last_update_frame = frame;
5621 if (!_dragging_playhead) {
5622 playhead_cursor->set_position (frame);
5625 if (!_stationary_playhead) {
5627 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5628 /* We only do this if we aren't already
5629 handling a visual change (ie if
5630 pending_visual_change.being_handled is
5631 false) so that these requests don't stack
5632 up there are too many of them to handle in
5635 reset_x_origin_to_follow_playhead ();
5640 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5641 framepos_t const frame = playhead_cursor->current_frame ();
5642 double target = ((double)frame - (double)current_page_samples()/2.0);
5643 if (target <= 0.0) {
5646 // compare to EditorCursor::set_position()
5647 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5648 double const new_pos = sample_to_pixel_unrounded (target);
5649 if (rint (new_pos) != rint (old_pos)) {
5650 reset_x_origin (pixel_to_sample (floor (new_pos)));
5661 Editor::session_going_away ()
5663 _have_idled = false;
5665 _session_connections.drop_connections ();
5667 super_rapid_screen_update_connection.disconnect ();
5669 selection->clear ();
5670 cut_buffer->clear ();
5672 clicked_regionview = 0;
5673 clicked_axisview = 0;
5674 clicked_routeview = 0;
5675 entered_regionview = 0;
5677 last_update_frame = 0;
5680 playhead_cursor->hide ();
5682 /* rip everything out of the list displays */
5686 _route_groups->clear ();
5688 /* do this first so that deleting a track doesn't reset cms to null
5689 and thus cause a leak.
5692 if (current_mixer_strip) {
5693 if (current_mixer_strip->get_parent() != 0) {
5694 global_hpacker.remove (*current_mixer_strip);
5696 delete current_mixer_strip;
5697 current_mixer_strip = 0;
5700 /* delete all trackviews */
5702 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5705 track_views.clear ();
5707 nudge_clock->set_session (0);
5709 editor_list_button.set_active(false);
5710 editor_list_button.set_sensitive(false);
5712 /* clear tempo/meter rulers */
5713 remove_metric_marks ();
5715 clear_marker_display ();
5717 stop_step_editing ();
5721 /* get rid of any existing editor mixer strip */
5723 WindowTitle title(Glib::get_application_name());
5724 title += _("Editor");
5726 own_window()->set_title (title.get_string());
5729 SessionHandlePtr::session_going_away ();
5733 Editor::trigger_script (int i)
5735 LuaInstance::instance()-> call_action (i);
5739 Editor::set_script_action_name (int i, const std::string& n)
5741 string const a = string_compose (X_("script-action-%1"), i + 1);
5742 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5745 act->set_label (string_compose (_("Unset #%1"), i + 1));
5746 act->set_tooltip (_("no action bound"));
5747 act->set_sensitive (false);
5750 act->set_tooltip (n);
5751 act->set_sensitive (true);
5753 KeyEditor::UpdateBindings ();
5757 Editor::show_editor_list (bool yn)
5760 _the_notebook.show ();
5762 _the_notebook.hide ();
5767 Editor::change_region_layering_order (bool from_context_menu)
5769 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5771 if (!clicked_routeview) {
5772 if (layering_order_editor) {
5773 layering_order_editor->hide ();
5778 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5784 boost::shared_ptr<Playlist> pl = track->playlist();
5790 if (layering_order_editor == 0) {
5791 layering_order_editor = new RegionLayeringOrderEditor (*this);
5794 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5795 layering_order_editor->maybe_present ();
5799 Editor::update_region_layering_order_editor ()
5801 if (layering_order_editor && layering_order_editor->is_visible ()) {
5802 change_region_layering_order (true);
5807 Editor::setup_fade_images ()
5809 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5810 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5811 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5812 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5813 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5815 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5816 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5817 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5818 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5819 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5821 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5822 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5823 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5824 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5825 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5827 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5828 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5829 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5830 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5831 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5835 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5837 Editor::action_menu_item (std::string const & name)
5839 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5842 return *manage (a->create_menu_item ());
5846 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5848 EventBox* b = manage (new EventBox);
5849 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5850 Label* l = manage (new Label (name));
5854 _the_notebook.append_page (widget, *b);
5858 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5860 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5861 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5864 if (ev->type == GDK_2BUTTON_PRESS) {
5866 /* double-click on a notebook tab shrinks or expands the notebook */
5868 if (_notebook_shrunk) {
5869 if (pre_notebook_shrink_pane_width) {
5870 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
5872 _notebook_shrunk = false;
5874 pre_notebook_shrink_pane_width = edit_pane.get_divider();
5876 /* this expands the LHS of the edit pane to cover the notebook
5877 PAGE but leaves the tabs visible.
5879 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
5880 _notebook_shrunk = true;
5888 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5890 using namespace Menu_Helpers;
5892 MenuList& items = _control_point_context_menu.items ();
5895 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5896 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5897 if (!can_remove_control_point (item)) {
5898 items.back().set_sensitive (false);
5901 _control_point_context_menu.popup (event->button.button, event->button.time);
5905 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5907 using namespace Menu_Helpers;
5909 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5914 /* We need to get the selection here and pass it to the operations, since
5915 popping up the menu will cause a region leave event which clears
5916 entered_regionview. */
5918 MidiRegionView& mrv = note->region_view();
5919 const RegionSelection rs = get_regions_from_selection_and_entered ();
5920 const uint32_t sel_size = mrv.selection_size ();
5922 MenuList& items = _note_context_menu.items();
5926 items.push_back(MenuElem(_("Delete"),
5927 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5930 items.push_back(MenuElem(_("Edit..."),
5931 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5932 if (sel_size != 1) {
5933 items.back().set_sensitive (false);
5936 items.push_back(MenuElem(_("Transpose..."),
5937 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
5940 items.push_back(MenuElem(_("Legatize"),
5941 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5943 items.back().set_sensitive (false);
5946 items.push_back(MenuElem(_("Quantize..."),
5947 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5949 items.push_back(MenuElem(_("Remove Overlap"),
5950 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5952 items.back().set_sensitive (false);
5955 items.push_back(MenuElem(_("Transform..."),
5956 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5958 _note_context_menu.popup (event->button.button, event->button.time);
5962 Editor::zoom_vertical_modifier_released()
5964 _stepping_axis_view = 0;
5968 Editor::ui_parameter_changed (string parameter)
5970 if (parameter == "icon-set") {
5971 while (!_cursor_stack.empty()) {
5972 _cursor_stack.pop_back();
5974 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
5975 _cursor_stack.push_back(_cursors->grabber);
5976 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
5977 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
5979 } else if (parameter == "draggable-playhead") {
5980 if (_verbose_cursor) {
5981 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
5987 Editor::use_own_window (bool and_fill_it)
5989 bool new_window = !own_window();
5991 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
5993 if (win && new_window) {
5994 win->set_name ("EditorWindow");
5996 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
5998 // win->signal_realize().connect (*this, &Editor::on_realize);
5999 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6000 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6001 win->set_data ("ardour-bindings", bindings);
6006 DisplaySuspender ds;
6007 contents().show_all ();
6009 /* XXX: this is a bit unfortunate; it would probably
6010 be nicer if we could just call show () above rather
6011 than needing the show_all ()
6014 /* re-hide stuff if necessary */
6015 editor_list_button_toggled ();
6016 parameter_changed ("show-summary");
6017 parameter_changed ("show-group-tabs");
6018 parameter_changed ("show-zoom-tools");
6020 /* now reset all audio_time_axis heights, because widgets might need
6026 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6027 tv = (static_cast<TimeAxisView*>(*i));
6028 tv->reset_height ();
6031 if (current_mixer_strip) {
6032 current_mixer_strip->hide_things ();
6033 current_mixer_strip->parameter_changed ("mixer-element-visibility");