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/tearoff.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/audio_track.h"
69 #include "ardour/audioengine.h"
70 #include "ardour/audioregion.h"
71 #include "ardour/lmath.h"
72 #include "ardour/location.h"
73 #include "ardour/profile.h"
74 #include "ardour/route_group.h"
75 #include "ardour/session_playlists.h"
76 #include "ardour/tempo.h"
77 #include "ardour/utils.h"
79 #include "canvas/debug.h"
80 #include "canvas/text.h"
82 #include "control_protocol/control_protocol.h"
85 #include "analysis_window.h"
86 #include "audio_clock.h"
87 #include "audio_region_view.h"
88 #include "audio_streamview.h"
89 #include "audio_time_axis.h"
90 #include "automation_time_axis.h"
91 #include "bundle_manager.h"
92 #include "crossfade_edit.h"
96 #include "editor_cursors.h"
97 #include "editor_drag.h"
98 #include "editor_group_tabs.h"
99 #include "editor_locations.h"
100 #include "editor_regions.h"
101 #include "editor_route_groups.h"
102 #include "editor_routes.h"
103 #include "editor_snapshots.h"
104 #include "editor_summary.h"
105 #include "global_port_matrix.h"
106 #include "gui_object.h"
107 #include "gui_thread.h"
108 #include "keyboard.h"
110 #include "midi_region_view.h"
111 #include "midi_time_axis.h"
112 #include "mixer_strip.h"
113 #include "mixer_ui.h"
114 #include "mouse_cursors.h"
115 #include "note_base.h"
116 #include "playlist_selector.h"
117 #include "public_editor.h"
118 #include "quantize_dialog.h"
119 #include "region_layering_order_editor.h"
120 #include "rgb_macros.h"
121 #include "rhythm_ferret.h"
122 #include "selection.h"
124 #include "tempo_lines.h"
125 #include "time_axis_view.h"
127 #include "tooltips.h"
128 #include "ui_config.h"
130 #include "verbose_cursor.h"
135 using namespace ARDOUR;
136 using namespace ARDOUR_UI_UTILS;
139 using namespace Glib;
140 using namespace Gtkmm2ext;
141 using namespace Editing;
143 using PBD::internationalize;
145 using Gtkmm2ext::Keyboard;
147 double Editor::timebar_height = 15.0;
149 static const gchar *_snap_type_strings[] = {
183 static const gchar *_snap_mode_strings[] = {
190 static const gchar *_edit_point_strings[] = {
197 static const gchar *_edit_mode_strings[] = {
205 static const gchar *_zoom_focus_strings[] = {
215 #ifdef USE_RUBBERBAND
216 static const gchar *_rb_opt_strings[] = {
219 N_("Balanced multitimbral mixture"),
220 N_("Unpitched percussion with stable notes"),
221 N_("Crisp monophonic instrumental"),
222 N_("Unpitched solo percussion"),
223 N_("Resample without preserving pitch"),
228 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
231 pane_size_watcher (Paned* pane)
233 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
237 Quartz: impossible to access
239 so stop that by preventing it from ever getting too narrow. 35
240 pixels is basically a rough guess at the tab width.
245 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
247 gint pos = pane->get_position ();
249 if (pos > max_width_of_lhs) {
250 pane->set_position (max_width_of_lhs);
255 : PublicEditor (global_hpacker)
256 , editor_mixer_strip_width (Wide)
257 , constructed (false)
258 , _playlist_selector (0)
259 , no_save_visual (false)
261 , samples_per_pixel (2048)
262 , zoom_focus (ZoomFocusPlayhead)
263 , mouse_mode (MouseObject)
264 , pre_internal_snap_type (SnapToBeat)
265 , pre_internal_snap_mode (SnapOff)
266 , internal_snap_type (SnapToBeat)
267 , internal_snap_mode (SnapOff)
268 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
269 , _notebook_shrunk (false)
270 , location_marker_color (0)
271 , location_range_color (0)
272 , location_loop_color (0)
273 , location_punch_color (0)
274 , location_cd_marker_color (0)
276 , _show_marker_lines (false)
277 , clicked_axisview (0)
278 , clicked_routeview (0)
279 , clicked_regionview (0)
280 , clicked_selection (0)
281 , clicked_control_point (0)
282 , button_release_can_deselect (true)
283 , _mouse_changed_selection (false)
284 , region_edit_menu_split_item (0)
285 , region_edit_menu_split_multichannel_item (0)
286 , track_region_edit_playlist_menu (0)
287 , track_edit_playlist_submenu (0)
288 , track_selection_edit_playlist_submenu (0)
289 , _popup_region_menu_item (0)
290 , global_vpacker (key_bindings)
292 , _track_canvas_viewport (0)
293 , within_track_canvas (false)
294 , _verbose_cursor (0)
299 , range_marker_group (0)
300 , transport_marker_group (0)
301 , cd_marker_group (0)
302 , _time_markers_group (0)
303 , hv_scroll_group (0)
305 , cursor_scroll_group (0)
306 , no_scroll_group (0)
307 , _trackview_group (0)
308 , _drag_motion_group (0)
309 , _canvas_drop_zone (0)
310 , no_ruler_shown_update (false)
311 , ruler_grabbed_widget (0)
313 , minsec_mark_interval (0)
314 , minsec_mark_modulo (0)
316 , timecode_mark_modulo (0)
317 , timecode_nmarks (0)
318 , _samples_ruler_interval (0)
321 , bbt_bar_helper_on (0)
322 , bbt_accent_modulo (0)
327 , visible_timebars (0)
328 , editor_ruler_menu (0)
332 , range_marker_bar (0)
333 , transport_marker_bar (0)
335 , minsec_label (_("Mins:Secs"))
336 , bbt_label (_("Bars:Beats"))
337 , timecode_label (_("Timecode"))
338 , samples_label (_("Samples"))
339 , tempo_label (_("Tempo"))
340 , meter_label (_("Meter"))
341 , mark_label (_("Location Markers"))
342 , range_mark_label (_("Range Markers"))
343 , transport_mark_label (_("Loop/Punch Ranges"))
344 , cd_mark_label (_("CD Markers"))
345 , videotl_label (_("Video Timeline"))
347 , playhead_cursor (0)
348 , edit_packer (4, 4, true)
349 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
350 , horizontal_adjustment (0.0, 0.0, 1e16)
351 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
352 , controls_layout (unused_adjustment, vertical_adjustment)
353 , _scroll_callbacks (0)
354 , _visible_canvas_width (0)
355 , _visible_canvas_height (0)
356 , _full_canvas_height (0)
357 , edit_controls_left_menu (0)
358 , edit_controls_right_menu (0)
359 , last_update_frame (0)
360 , cut_buffer_start (0)
361 , cut_buffer_length (0)
362 , button_bindings (0)
366 , current_interthread_info (0)
367 , analysis_window (0)
368 , select_new_marker (false)
370 , scrubbing_direction (0)
371 , scrub_reversals (0)
372 , scrub_reverse_distance (0)
373 , have_pending_keyboard_selection (false)
374 , pending_keyboard_selection_start (0)
375 , _snap_type (SnapToBeat)
376 , _snap_mode (SnapOff)
377 , snap_threshold (5.0)
378 , ignore_gui_changes (false)
379 , _drags (new DragManager (this))
381 , last_event_time { 0, 0 }
382 , _dragging_playhead (false)
383 , _dragging_edit_point (false)
384 , _show_measures (true)
385 , _follow_playhead (true)
386 , _stationary_playhead (false)
389 , global_rect_group (0)
390 , time_line_group (0)
391 , tempo_or_meter_marker_menu (0)
393 , range_marker_menu (0)
394 , transport_marker_menu (0)
395 , new_transport_marker_menu (0)
397 , marker_menu_item (0)
398 , bbt_beat_subdivision (4)
399 , _visible_track_count (-1)
400 , toolbar_selection_clock_table (2,3)
401 , _mouse_mode_tearoff (0)
402 , automation_mode_button (_("mode"))
405 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
406 , selection (new Selection (this))
407 , cut_buffer (new Selection (this))
408 , _selection_memento (new SelectionMemento())
409 , _all_region_actions_sensitized (false)
410 , _ignore_region_action (false)
411 , _last_region_menu_was_main (false)
412 , _ignore_follow_edits (false)
413 , cd_marker_bar_drag_rect (0)
414 , range_bar_drag_rect (0)
415 , transport_bar_drag_rect (0)
416 , transport_bar_range_rect (0)
417 , transport_bar_preroll_rect (0)
418 , transport_bar_postroll_rect (0)
419 , transport_loop_range_rect (0)
420 , transport_punch_range_rect (0)
421 , transport_punchin_line (0)
422 , transport_punchout_line (0)
423 , transport_preroll_rect (0)
424 , transport_postroll_rect (0)
426 , rubberband_rect (0)
432 , autoscroll_horizontal_allowed (false)
433 , autoscroll_vertical_allowed (false)
435 , autoscroll_widget (0)
436 , show_gain_after_trim (false)
437 , selection_op_cmd_depth (0)
438 , selection_op_history_it (0)
440 , current_mixer_strip (0)
441 , show_editor_mixer_when_tracks_arrive (false)
442 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
443 , current_stepping_trackview (0)
444 , last_track_height_step_timestamp (0)
446 , entered_regionview (0)
447 , clear_entered_track (false)
448 , _edit_point (EditAtMouse)
449 , meters_running (false)
451 , _have_idled (false)
452 , resize_idle_id (-1)
453 , _pending_resize_amount (0)
454 , _pending_resize_view (0)
455 , _pending_locate_request (false)
456 , _pending_initial_locate (false)
460 , layering_order_editor (0)
461 , _last_cut_copy_source_track (0)
462 , _region_selection_change_updates_region_list (true)
464 , _following_mixer_selection (false)
465 , _control_point_toggled_on_press (false)
466 , _stepping_axis_view (0)
467 , quantize_dialog (0)
468 , _main_menu_disabler (0)
470 /* we are a singleton */
472 PublicEditor::_instance = this;
476 selection_op_history.clear();
479 snap_type_strings = I18N (_snap_type_strings);
480 snap_mode_strings = I18N (_snap_mode_strings);
481 zoom_focus_strings = I18N (_zoom_focus_strings);
482 edit_mode_strings = I18N (_edit_mode_strings);
483 edit_point_strings = I18N (_edit_point_strings);
484 #ifdef USE_RUBBERBAND
485 rb_opt_strings = I18N (_rb_opt_strings);
489 build_edit_mode_menu();
490 build_zoom_focus_menu();
491 build_track_count_menu();
492 build_snap_mode_menu();
493 build_snap_type_menu();
494 build_edit_point_menu();
496 location_marker_color = ARDOUR_UI::config()->color ("location marker");
497 location_range_color = ARDOUR_UI::config()->color ("location range");
498 location_cd_marker_color = ARDOUR_UI::config()->color ("location cd marker");
499 location_loop_color = ARDOUR_UI::config()->color ("location loop");
500 location_punch_color = ARDOUR_UI::config()->color ("location punch");
502 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
504 TimeAxisView::setup_sizes ();
505 ArdourMarker::setup_sizes (timebar_height);
507 bbt_label.set_name ("EditorRulerLabel");
508 bbt_label.set_size_request (-1, (int)timebar_height);
509 bbt_label.set_alignment (1.0, 0.5);
510 bbt_label.set_padding (5,0);
512 bbt_label.set_no_show_all();
513 minsec_label.set_name ("EditorRulerLabel");
514 minsec_label.set_size_request (-1, (int)timebar_height);
515 minsec_label.set_alignment (1.0, 0.5);
516 minsec_label.set_padding (5,0);
517 minsec_label.hide ();
518 minsec_label.set_no_show_all();
519 timecode_label.set_name ("EditorRulerLabel");
520 timecode_label.set_size_request (-1, (int)timebar_height);
521 timecode_label.set_alignment (1.0, 0.5);
522 timecode_label.set_padding (5,0);
523 timecode_label.hide ();
524 timecode_label.set_no_show_all();
525 samples_label.set_name ("EditorRulerLabel");
526 samples_label.set_size_request (-1, (int)timebar_height);
527 samples_label.set_alignment (1.0, 0.5);
528 samples_label.set_padding (5,0);
529 samples_label.hide ();
530 samples_label.set_no_show_all();
532 tempo_label.set_name ("EditorRulerLabel");
533 tempo_label.set_size_request (-1, (int)timebar_height);
534 tempo_label.set_alignment (1.0, 0.5);
535 tempo_label.set_padding (5,0);
537 tempo_label.set_no_show_all();
539 meter_label.set_name ("EditorRulerLabel");
540 meter_label.set_size_request (-1, (int)timebar_height);
541 meter_label.set_alignment (1.0, 0.5);
542 meter_label.set_padding (5,0);
544 meter_label.set_no_show_all();
546 if (Profile->get_trx()) {
547 mark_label.set_text (_("Markers"));
549 mark_label.set_name ("EditorRulerLabel");
550 mark_label.set_size_request (-1, (int)timebar_height);
551 mark_label.set_alignment (1.0, 0.5);
552 mark_label.set_padding (5,0);
554 mark_label.set_no_show_all();
556 cd_mark_label.set_name ("EditorRulerLabel");
557 cd_mark_label.set_size_request (-1, (int)timebar_height);
558 cd_mark_label.set_alignment (1.0, 0.5);
559 cd_mark_label.set_padding (5,0);
560 cd_mark_label.hide();
561 cd_mark_label.set_no_show_all();
563 videotl_bar_height = 4;
564 videotl_label.set_name ("EditorRulerLabel");
565 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
566 videotl_label.set_alignment (1.0, 0.5);
567 videotl_label.set_padding (5,0);
568 videotl_label.hide();
569 videotl_label.set_no_show_all();
571 range_mark_label.set_name ("EditorRulerLabel");
572 range_mark_label.set_size_request (-1, (int)timebar_height);
573 range_mark_label.set_alignment (1.0, 0.5);
574 range_mark_label.set_padding (5,0);
575 range_mark_label.hide();
576 range_mark_label.set_no_show_all();
578 transport_mark_label.set_name ("EditorRulerLabel");
579 transport_mark_label.set_size_request (-1, (int)timebar_height);
580 transport_mark_label.set_alignment (1.0, 0.5);
581 transport_mark_label.set_padding (5,0);
582 transport_mark_label.hide();
583 transport_mark_label.set_no_show_all();
585 initialize_canvas ();
587 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
589 _summary = new EditorSummary (this);
591 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
592 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
594 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
596 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
597 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
599 edit_controls_vbox.set_spacing (0);
600 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
601 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
603 HBox* h = manage (new HBox);
604 _group_tabs = new EditorGroupTabs (this);
605 if (!ARDOUR::Profile->get_trx()) {
606 h->pack_start (*_group_tabs, PACK_SHRINK);
608 h->pack_start (edit_controls_vbox);
609 controls_layout.add (*h);
611 controls_layout.set_name ("EditControlsBase");
612 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
613 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
614 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
616 _cursors = new MouseCursors;
617 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
618 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
620 /* Push default cursor to ever-present bottom of cursor stack. */
621 push_canvas_cursor(_cursors->grabber);
623 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
625 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
626 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
627 pad_line_1->set_outline_color (0xFF0000FF);
633 edit_packer.set_col_spacings (0);
634 edit_packer.set_row_spacings (0);
635 edit_packer.set_homogeneous (false);
636 edit_packer.set_border_width (0);
637 edit_packer.set_name ("EditorWindow");
639 time_bars_event_box.add (time_bars_vbox);
640 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
641 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
643 /* labels for the time bars */
644 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
646 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
648 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
650 bottom_hbox.set_border_width (2);
651 bottom_hbox.set_spacing (3);
653 _route_groups = new EditorRouteGroups (this);
654 _routes = new EditorRoutes (this);
655 _regions = new EditorRegions (this);
656 _snapshots = new EditorSnapshots (this);
657 _locations = new EditorLocations (this);
659 /* these are static location signals */
661 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
662 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
663 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
665 add_notebook_page (_("Regions"), _regions->widget ());
666 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
667 add_notebook_page (_("Snapshots"), _snapshots->widget ());
668 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
669 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
671 _the_notebook.set_show_tabs (true);
672 _the_notebook.set_scrollable (true);
673 _the_notebook.popup_disable ();
674 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
675 _the_notebook.show_all ();
677 _notebook_shrunk = false;
679 editor_summary_pane.pack1(edit_packer);
681 Button* summary_arrows_left_left = manage (new Button);
682 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
683 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
684 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
686 Button* summary_arrows_left_right = manage (new Button);
687 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
688 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
689 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
691 VBox* summary_arrows_left = manage (new VBox);
692 summary_arrows_left->pack_start (*summary_arrows_left_left);
693 summary_arrows_left->pack_start (*summary_arrows_left_right);
695 Button* summary_arrows_right_up = manage (new Button);
696 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
697 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
698 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
700 Button* summary_arrows_right_down = manage (new Button);
701 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
702 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
703 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
705 VBox* summary_arrows_right = manage (new VBox);
706 summary_arrows_right->pack_start (*summary_arrows_right_up);
707 summary_arrows_right->pack_start (*summary_arrows_right_down);
709 Frame* summary_frame = manage (new Frame);
710 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
712 summary_frame->add (*_summary);
713 summary_frame->show ();
715 _summary_hbox.pack_start (*summary_arrows_left, false, false);
716 _summary_hbox.pack_start (*summary_frame, true, true);
717 _summary_hbox.pack_start (*summary_arrows_right, false, false);
719 if (!ARDOUR::Profile->get_trx()) {
720 editor_summary_pane.pack2 (_summary_hbox);
723 edit_pane.pack1 (editor_summary_pane, true, true);
724 if (!ARDOUR::Profile->get_trx()) {
725 edit_pane.pack2 (_the_notebook, false, true);
728 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
730 /* XXX: editor_summary_pane might need similar to the edit_pane */
732 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
734 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
735 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
737 top_hbox.pack_start (toolbar_frame);
739 HBox *hbox = manage (new HBox);
740 hbox->pack_start (edit_pane, true, true);
742 global_vpacker.pack_start (top_hbox, false, false);
743 global_vpacker.pack_start (*hbox, true, true);
744 global_hpacker.pack_start (global_vpacker, true, true);
746 /* register actions now so that set_state() can find them and set toggles/checks etc */
749 /* when we start using our own keybinding system for the editor, this
750 * will be uncommented
756 _playlist_selector = new PlaylistSelector();
757 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
759 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
763 nudge_forward_button.set_name ("nudge button");
764 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
766 nudge_backward_button.set_name ("nudge button");
767 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
769 fade_context_menu.set_name ("ArdourContextMenu");
771 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
773 /* allow external control surfaces/protocols to do various things */
775 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
776 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
777 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
778 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
779 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
780 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
781 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
782 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
783 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
784 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
785 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
786 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
787 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
788 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
790 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
791 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
792 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
793 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
794 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
796 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
798 /* problematic: has to return a value and thus cannot be x-thread */
800 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
802 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
803 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
805 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
807 _ignore_region_action = false;
808 _last_region_menu_was_main = false;
809 _popup_region_menu_item = 0;
811 _ignore_follow_edits = false;
813 _show_marker_lines = false;
815 /* Button bindings */
817 button_bindings = new Bindings;
819 XMLNode* node = button_settings();
821 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
822 button_bindings->load (**i);
828 /* grab current parameter state */
829 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
830 UIConfiguration::instance().map_parameters (pc);
832 setup_fade_images ();
839 delete button_bindings;
841 delete _route_groups;
842 delete _track_canvas_viewport;
845 delete quantize_dialog;
851 delete _playlist_selector;
853 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
859 Editor::button_settings () const
861 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
862 XMLNode* node = find_named_node (*settings, X_("Buttons"));
865 node = new XMLNode (X_("Buttons"));
872 Editor::get_smart_mode () const
874 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
878 Editor::catch_vanishing_regionview (RegionView *rv)
880 /* note: the selection will take care of the vanishing
881 audioregionview by itself.
884 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
888 if (clicked_regionview == rv) {
889 clicked_regionview = 0;
892 if (entered_regionview == rv) {
893 set_entered_regionview (0);
896 if (!_all_region_actions_sensitized) {
897 sensitize_all_region_actions (true);
902 Editor::set_entered_regionview (RegionView* rv)
904 if (rv == entered_regionview) {
908 if (entered_regionview) {
909 entered_regionview->exited ();
912 entered_regionview = rv;
914 if (entered_regionview != 0) {
915 entered_regionview->entered ();
918 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
919 /* This RegionView entry might have changed what region actions
920 are allowed, so sensitize them all in case a key is pressed.
922 sensitize_all_region_actions (true);
927 Editor::set_entered_track (TimeAxisView* tav)
930 entered_track->exited ();
936 entered_track->entered ();
941 Editor::instant_save ()
943 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
948 _session->add_instant_xml(get_state());
950 Config->add_instant_xml(get_state());
955 Editor::control_vertical_zoom_in_all ()
957 tav_zoom_smooth (false, true);
961 Editor::control_vertical_zoom_out_all ()
963 tav_zoom_smooth (true, true);
967 Editor::control_vertical_zoom_in_selected ()
969 tav_zoom_smooth (false, false);
973 Editor::control_vertical_zoom_out_selected ()
975 tav_zoom_smooth (true, false);
979 Editor::control_view (uint32_t view)
981 goto_visual_state (view);
985 Editor::control_unselect ()
987 selection->clear_tracks ();
991 Editor::control_select (uint32_t rid, Selection::Operation op)
993 /* handles the (static) signal from the ControlProtocol class that
994 * requests setting the selected track to a given RID
1001 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1007 TimeAxisView* tav = axis_view_from_route (r);
1011 case Selection::Add:
1012 selection->add (tav);
1014 case Selection::Toggle:
1015 selection->toggle (tav);
1017 case Selection::Extend:
1019 case Selection::Set:
1020 selection->set (tav);
1024 selection->clear_tracks ();
1029 Editor::control_step_tracks_up ()
1031 scroll_tracks_up_line ();
1035 Editor::control_step_tracks_down ()
1037 scroll_tracks_down_line ();
1041 Editor::control_scroll (float fraction)
1043 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1049 double step = fraction * current_page_samples();
1052 _control_scroll_target is an optional<T>
1054 it acts like a pointer to an framepos_t, with
1055 a operator conversion to boolean to check
1056 that it has a value could possibly use
1057 playhead_cursor->current_frame to store the
1058 value and a boolean in the class to know
1059 when it's out of date
1062 if (!_control_scroll_target) {
1063 _control_scroll_target = _session->transport_frame();
1064 _dragging_playhead = true;
1067 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1068 *_control_scroll_target = 0;
1069 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1070 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1072 *_control_scroll_target += (framepos_t) trunc (step);
1075 /* move visuals, we'll catch up with it later */
1077 playhead_cursor->set_position (*_control_scroll_target);
1078 UpdateAllTransportClocks (*_control_scroll_target);
1080 if (*_control_scroll_target > (current_page_samples() / 2)) {
1081 /* try to center PH in window */
1082 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1088 Now we do a timeout to actually bring the session to the right place
1089 according to the playhead. This is to avoid reading disk buffers on every
1090 call to control_scroll, which is driven by ScrollTimeline and therefore
1091 probably by a control surface wheel which can generate lots of events.
1093 /* cancel the existing timeout */
1095 control_scroll_connection.disconnect ();
1097 /* add the next timeout */
1099 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1103 Editor::deferred_control_scroll (framepos_t /*target*/)
1105 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1106 // reset for next stream
1107 _control_scroll_target = boost::none;
1108 _dragging_playhead = false;
1113 Editor::access_action (std::string action_group, std::string action_item)
1119 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1122 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1130 Editor::on_realize ()
1134 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1135 start_lock_event_timing ();
1140 Editor::start_lock_event_timing ()
1142 /* check if we should lock the GUI every 30 seconds */
1144 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1148 Editor::generic_event_handler (GdkEvent* ev)
1151 case GDK_BUTTON_PRESS:
1152 case GDK_BUTTON_RELEASE:
1153 case GDK_MOTION_NOTIFY:
1155 case GDK_KEY_RELEASE:
1156 if (contents().is_mapped()) {
1157 gettimeofday (&last_event_time, 0);
1161 case GDK_LEAVE_NOTIFY:
1162 switch (ev->crossing.detail) {
1163 case GDK_NOTIFY_UNKNOWN:
1164 case GDK_NOTIFY_INFERIOR:
1165 case GDK_NOTIFY_ANCESTOR:
1167 case GDK_NOTIFY_VIRTUAL:
1168 case GDK_NOTIFY_NONLINEAR:
1169 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1170 /* leaving window, so reset focus, thus ending any and
1171 all text entry operations.
1186 Editor::lock_timeout_callback ()
1188 struct timeval now, delta;
1190 gettimeofday (&now, 0);
1192 timersub (&now, &last_event_time, &delta);
1194 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1196 /* don't call again. Returning false will effectively
1197 disconnect us from the timer callback.
1199 unlock() will call start_lock_event_timing() to get things
1209 Editor::map_position_change (framepos_t frame)
1211 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1213 if (_session == 0) {
1217 if (_follow_playhead) {
1218 center_screen (frame);
1221 playhead_cursor->set_position (frame);
1225 Editor::center_screen (framepos_t frame)
1227 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1229 /* if we're off the page, then scroll.
1232 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1233 center_screen_internal (frame, page);
1238 Editor::center_screen_internal (framepos_t frame, float page)
1243 frame -= (framepos_t) page;
1248 reset_x_origin (frame);
1253 Editor::update_title ()
1255 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1257 if (!own_window()) {
1262 bool dirty = _session->dirty();
1264 string session_name;
1266 if (_session->snap_name() != _session->name()) {
1267 session_name = _session->snap_name();
1269 session_name = _session->name();
1273 session_name = "*" + session_name;
1276 WindowTitle title(session_name);
1277 title += Glib::get_application_name();
1278 own_window()->set_title (title.get_string());
1280 /* ::session_going_away() will have taken care of it */
1285 Editor::set_session (Session *t)
1287 SessionHandlePtr::set_session (t);
1293 _playlist_selector->set_session (_session);
1294 nudge_clock->set_session (_session);
1295 _summary->set_session (_session);
1296 _group_tabs->set_session (_session);
1297 _route_groups->set_session (_session);
1298 _regions->set_session (_session);
1299 _snapshots->set_session (_session);
1300 _routes->set_session (_session);
1301 _locations->set_session (_session);
1303 if (rhythm_ferret) {
1304 rhythm_ferret->set_session (_session);
1307 if (analysis_window) {
1308 analysis_window->set_session (_session);
1312 sfbrowser->set_session (_session);
1315 compute_fixed_ruler_scale ();
1317 /* Make sure we have auto loop and auto punch ranges */
1319 Location* loc = _session->locations()->auto_loop_location();
1321 loc->set_name (_("Loop"));
1324 loc = _session->locations()->auto_punch_location();
1327 loc->set_name (_("Punch"));
1330 refresh_location_display ();
1332 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1333 the selected Marker; this needs the LocationMarker list to be available.
1335 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1336 set_state (*node, Stateful::loading_state_version);
1338 /* catch up with the playhead */
1340 _session->request_locate (playhead_cursor->current_frame ());
1341 _pending_initial_locate = true;
1345 /* These signals can all be emitted by a non-GUI thread. Therefore the
1346 handlers for them must not attempt to directly interact with the GUI,
1347 but use PBD::Signal<T>::connect() which accepts an event loop
1348 ("context") where the handler will be asked to run.
1351 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1352 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1353 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1354 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1355 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1356 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1357 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1358 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1359 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1360 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1361 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1362 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1363 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1365 playhead_cursor->show ();
1367 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1368 Config->map_parameters (pc);
1369 _session->config.map_parameters (pc);
1371 restore_ruler_visibility ();
1372 //tempo_map_changed (PropertyChange (0));
1373 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1375 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1376 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1379 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1380 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1383 switch (_snap_type) {
1384 case SnapToRegionStart:
1385 case SnapToRegionEnd:
1386 case SnapToRegionSync:
1387 case SnapToRegionBoundary:
1388 build_region_boundary_cache ();
1395 /* register for undo history */
1396 _session->register_with_memento_command_factory(id(), this);
1397 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1399 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1401 start_updating_meters ();
1405 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1407 if (a->get_name() == "RegionMenu") {
1408 /* When the main menu's region menu is opened, we setup the actions so that they look right
1409 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1410 so we resensitize all region actions when the entered regionview or the region selection
1411 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1412 happens after the region context menu is opened. So we set a flag here, too.
1416 sensitize_the_right_region_actions ();
1417 _last_region_menu_was_main = true;
1422 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1424 using namespace Menu_Helpers;
1426 void (Editor::*emf)(FadeShape);
1427 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1430 images = &_xfade_in_images;
1431 emf = &Editor::set_fade_in_shape;
1433 images = &_xfade_out_images;
1434 emf = &Editor::set_fade_out_shape;
1439 _("Linear (for highly correlated material)"),
1440 *(*images)[FadeLinear],
1441 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1445 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1449 _("Constant power"),
1450 *(*images)[FadeConstantPower],
1451 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1454 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1459 *(*images)[FadeSymmetric],
1460 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1464 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1469 *(*images)[FadeSlow],
1470 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1473 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1478 *(*images)[FadeFast],
1479 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1482 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1485 /** Pop up a context menu for when the user clicks on a start crossfade */
1487 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1489 using namespace Menu_Helpers;
1490 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1495 MenuList& items (xfade_in_context_menu.items());
1498 if (arv->audio_region()->fade_in_active()) {
1499 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1501 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1504 items.push_back (SeparatorElem());
1505 fill_xfade_menu (items, true);
1507 xfade_in_context_menu.popup (button, time);
1510 /** Pop up a context menu for when the user clicks on an end crossfade */
1512 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1514 using namespace Menu_Helpers;
1515 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1520 MenuList& items (xfade_out_context_menu.items());
1523 if (arv->audio_region()->fade_out_active()) {
1524 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1526 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1529 items.push_back (SeparatorElem());
1530 fill_xfade_menu (items, false);
1532 xfade_out_context_menu.popup (button, time);
1536 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1538 using namespace Menu_Helpers;
1539 Menu* (Editor::*build_menu_function)();
1542 switch (item_type) {
1544 case RegionViewName:
1545 case RegionViewNameHighlight:
1546 case LeftFrameHandle:
1547 case RightFrameHandle:
1548 if (with_selection) {
1549 build_menu_function = &Editor::build_track_selection_context_menu;
1551 build_menu_function = &Editor::build_track_region_context_menu;
1556 if (with_selection) {
1557 build_menu_function = &Editor::build_track_selection_context_menu;
1559 build_menu_function = &Editor::build_track_context_menu;
1564 if (clicked_routeview->track()) {
1565 build_menu_function = &Editor::build_track_context_menu;
1567 build_menu_function = &Editor::build_track_bus_context_menu;
1572 /* probably shouldn't happen but if it does, we don't care */
1576 menu = (this->*build_menu_function)();
1577 menu->set_name ("ArdourContextMenu");
1579 /* now handle specific situations */
1581 switch (item_type) {
1583 case RegionViewName:
1584 case RegionViewNameHighlight:
1585 case LeftFrameHandle:
1586 case RightFrameHandle:
1587 if (!with_selection) {
1588 if (region_edit_menu_split_item) {
1589 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1590 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1592 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1595 if (region_edit_menu_split_multichannel_item) {
1596 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1597 region_edit_menu_split_multichannel_item->set_sensitive (true);
1599 region_edit_menu_split_multichannel_item->set_sensitive (false);
1612 /* probably shouldn't happen but if it does, we don't care */
1616 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1618 /* Bounce to disk */
1620 using namespace Menu_Helpers;
1621 MenuList& edit_items = menu->items();
1623 edit_items.push_back (SeparatorElem());
1625 switch (clicked_routeview->audio_track()->freeze_state()) {
1626 case AudioTrack::NoFreeze:
1627 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1630 case AudioTrack::Frozen:
1631 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1634 case AudioTrack::UnFrozen:
1635 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1641 if (item_type == StreamItem && clicked_routeview) {
1642 clicked_routeview->build_underlay_menu(menu);
1645 /* When the region menu is opened, we setup the actions so that they look right
1648 sensitize_the_right_region_actions ();
1649 _last_region_menu_was_main = false;
1651 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1652 menu->popup (button, time);
1656 Editor::build_track_context_menu ()
1658 using namespace Menu_Helpers;
1660 MenuList& edit_items = track_context_menu.items();
1663 add_dstream_context_items (edit_items);
1664 return &track_context_menu;
1668 Editor::build_track_bus_context_menu ()
1670 using namespace Menu_Helpers;
1672 MenuList& edit_items = track_context_menu.items();
1675 add_bus_context_items (edit_items);
1676 return &track_context_menu;
1680 Editor::build_track_region_context_menu ()
1682 using namespace Menu_Helpers;
1683 MenuList& edit_items = track_region_context_menu.items();
1686 /* we've just cleared the track region context menu, so the menu that these
1687 two items were on will have disappeared; stop them dangling.
1689 region_edit_menu_split_item = 0;
1690 region_edit_menu_split_multichannel_item = 0;
1692 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1695 boost::shared_ptr<Track> tr;
1696 boost::shared_ptr<Playlist> pl;
1698 if ((tr = rtv->track())) {
1699 add_region_context_items (edit_items, tr);
1703 add_dstream_context_items (edit_items);
1705 return &track_region_context_menu;
1709 Editor::analyze_region_selection ()
1711 if (analysis_window == 0) {
1712 analysis_window = new AnalysisWindow();
1715 analysis_window->set_session(_session);
1717 analysis_window->show_all();
1720 analysis_window->set_regionmode();
1721 analysis_window->analyze();
1723 analysis_window->present();
1727 Editor::analyze_range_selection()
1729 if (analysis_window == 0) {
1730 analysis_window = new AnalysisWindow();
1733 analysis_window->set_session(_session);
1735 analysis_window->show_all();
1738 analysis_window->set_rangemode();
1739 analysis_window->analyze();
1741 analysis_window->present();
1745 Editor::build_track_selection_context_menu ()
1747 using namespace Menu_Helpers;
1748 MenuList& edit_items = track_selection_context_menu.items();
1749 edit_items.clear ();
1751 add_selection_context_items (edit_items);
1752 // edit_items.push_back (SeparatorElem());
1753 // add_dstream_context_items (edit_items);
1755 return &track_selection_context_menu;
1759 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1761 using namespace Menu_Helpers;
1763 /* OK, stick the region submenu at the top of the list, and then add
1767 RegionSelection rs = get_regions_from_selection_and_entered ();
1769 string::size_type pos = 0;
1770 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1772 /* we have to hack up the region name because "_" has a special
1773 meaning for menu titles.
1776 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1777 menu_item_name.replace (pos, 1, "__");
1781 if (_popup_region_menu_item == 0) {
1782 _popup_region_menu_item = new MenuItem (menu_item_name);
1783 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1784 _popup_region_menu_item->show ();
1786 _popup_region_menu_item->set_label (menu_item_name);
1789 /* No latering allowed in later is higher layering model */
1790 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1791 if (act && Config->get_layer_model() == LaterHigher) {
1792 act->set_sensitive (false);
1794 act->set_sensitive (true);
1797 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1799 edit_items.push_back (*_popup_region_menu_item);
1800 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1801 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1803 edit_items.push_back (SeparatorElem());
1806 /** Add context menu items relevant to selection ranges.
1807 * @param edit_items List to add the items to.
1810 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1812 using namespace Menu_Helpers;
1814 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1815 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1817 edit_items.push_back (SeparatorElem());
1818 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1820 edit_items.push_back (SeparatorElem());
1821 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1823 edit_items.push_back (SeparatorElem());
1825 edit_items.push_back (
1827 _("Move Range Start to Previous Region Boundary"),
1828 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1832 edit_items.push_back (
1834 _("Move Range Start to Next Region Boundary"),
1835 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1839 edit_items.push_back (
1841 _("Move Range End to Previous Region Boundary"),
1842 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1846 edit_items.push_back (
1848 _("Move Range End to Next Region Boundary"),
1849 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1853 edit_items.push_back (SeparatorElem());
1854 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1855 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1857 edit_items.push_back (SeparatorElem());
1858 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1860 edit_items.push_back (SeparatorElem());
1861 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1862 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1863 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1865 edit_items.push_back (SeparatorElem());
1866 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1868 edit_items.push_back (SeparatorElem());
1869 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1870 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1872 edit_items.push_back (SeparatorElem());
1873 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1874 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1875 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1876 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1877 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1878 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1879 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1885 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1887 using namespace Menu_Helpers;
1891 Menu *play_menu = manage (new Menu);
1892 MenuList& play_items = play_menu->items();
1893 play_menu->set_name ("ArdourContextMenu");
1895 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1896 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1897 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1898 play_items.push_back (SeparatorElem());
1899 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1901 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1905 Menu *select_menu = manage (new Menu);
1906 MenuList& select_items = select_menu->items();
1907 select_menu->set_name ("ArdourContextMenu");
1909 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1910 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1911 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1912 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1913 select_items.push_back (SeparatorElem());
1914 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1915 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1916 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
1917 select_items.push_back (SeparatorElem());
1918 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
1919 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
1920 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1921 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1922 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1923 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1924 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1926 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1930 Menu *cutnpaste_menu = manage (new Menu);
1931 MenuList& cutnpaste_items = cutnpaste_menu->items();
1932 cutnpaste_menu->set_name ("ArdourContextMenu");
1934 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1935 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1936 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1938 cutnpaste_items.push_back (SeparatorElem());
1940 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1941 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1943 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1945 /* Adding new material */
1947 edit_items.push_back (SeparatorElem());
1948 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1949 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1953 Menu *nudge_menu = manage (new Menu());
1954 MenuList& nudge_items = nudge_menu->items();
1955 nudge_menu->set_name ("ArdourContextMenu");
1957 edit_items.push_back (SeparatorElem());
1958 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1959 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1960 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1961 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1963 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1967 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1969 using namespace Menu_Helpers;
1973 Menu *play_menu = manage (new Menu);
1974 MenuList& play_items = play_menu->items();
1975 play_menu->set_name ("ArdourContextMenu");
1977 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1978 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1979 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1983 Menu *select_menu = manage (new Menu);
1984 MenuList& select_items = select_menu->items();
1985 select_menu->set_name ("ArdourContextMenu");
1987 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1988 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1989 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1990 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1991 select_items.push_back (SeparatorElem());
1992 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
1993 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
1994 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1995 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1997 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2001 Menu *cutnpaste_menu = manage (new Menu);
2002 MenuList& cutnpaste_items = cutnpaste_menu->items();
2003 cutnpaste_menu->set_name ("ArdourContextMenu");
2005 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2006 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2007 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2009 Menu *nudge_menu = manage (new Menu());
2010 MenuList& nudge_items = nudge_menu->items();
2011 nudge_menu->set_name ("ArdourContextMenu");
2013 edit_items.push_back (SeparatorElem());
2014 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2015 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2016 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2017 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2019 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2023 Editor::snap_type() const
2029 Editor::snap_mode() const
2035 Editor::set_snap_to (SnapType st)
2037 unsigned int snap_ind = (unsigned int)st;
2039 if (internal_editing()) {
2040 internal_snap_type = st;
2042 pre_internal_snap_type = st;
2047 if (snap_ind > snap_type_strings.size() - 1) {
2049 _snap_type = (SnapType)snap_ind;
2052 string str = snap_type_strings[snap_ind];
2054 if (str != snap_type_selector.get_text()) {
2055 snap_type_selector.set_text (str);
2060 switch (_snap_type) {
2061 case SnapToBeatDiv128:
2062 case SnapToBeatDiv64:
2063 case SnapToBeatDiv32:
2064 case SnapToBeatDiv28:
2065 case SnapToBeatDiv24:
2066 case SnapToBeatDiv20:
2067 case SnapToBeatDiv16:
2068 case SnapToBeatDiv14:
2069 case SnapToBeatDiv12:
2070 case SnapToBeatDiv10:
2071 case SnapToBeatDiv8:
2072 case SnapToBeatDiv7:
2073 case SnapToBeatDiv6:
2074 case SnapToBeatDiv5:
2075 case SnapToBeatDiv4:
2076 case SnapToBeatDiv3:
2077 case SnapToBeatDiv2: {
2078 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2079 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2081 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2082 current_bbt_points_begin, current_bbt_points_end);
2083 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2084 current_bbt_points_begin, current_bbt_points_end);
2085 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2089 case SnapToRegionStart:
2090 case SnapToRegionEnd:
2091 case SnapToRegionSync:
2092 case SnapToRegionBoundary:
2093 build_region_boundary_cache ();
2101 redisplay_tempo (false);
2103 SnapChanged (); /* EMIT SIGNAL */
2107 Editor::set_snap_mode (SnapMode mode)
2109 string str = snap_mode_strings[(int)mode];
2111 if (internal_editing()) {
2112 internal_snap_mode = mode;
2114 pre_internal_snap_mode = mode;
2119 if (str != snap_mode_selector.get_text ()) {
2120 snap_mode_selector.set_text (str);
2127 Editor::set_edit_point_preference (EditPoint ep, bool force)
2129 bool changed = (_edit_point != ep);
2132 if (Profile->get_mixbus())
2133 if (ep == EditAtSelectedMarker)
2134 ep = EditAtPlayhead;
2136 string str = edit_point_strings[(int)ep];
2137 if (str != edit_point_selector.get_text ()) {
2138 edit_point_selector.set_text (str);
2141 update_all_enter_cursors();
2143 if (!force && !changed) {
2147 const char* action=NULL;
2149 switch (_edit_point) {
2150 case EditAtPlayhead:
2151 action = "edit-at-playhead";
2153 case EditAtSelectedMarker:
2154 action = "edit-at-marker";
2157 action = "edit-at-mouse";
2161 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2163 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2167 bool in_track_canvas;
2169 if (!mouse_frame (foo, in_track_canvas)) {
2170 in_track_canvas = false;
2173 reset_canvas_action_sensitivity (in_track_canvas);
2179 Editor::set_state (const XMLNode& node, int version)
2181 const XMLProperty* prop;
2185 Tabbable::set_state (node, version);
2187 if (_session && (prop = node.property ("playhead"))) {
2189 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2191 playhead_cursor->set_position (pos);
2193 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2194 playhead_cursor->set_position (0);
2197 playhead_cursor->set_position (0);
2200 if ((prop = node.property ("mixer-width"))) {
2201 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2204 if ((prop = node.property ("zoom-focus"))) {
2205 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2208 if ((prop = node.property ("zoom"))) {
2209 /* older versions of ardour used floating point samples_per_pixel */
2210 double f = PBD::atof (prop->value());
2211 reset_zoom (llrintf (f));
2213 reset_zoom (samples_per_pixel);
2216 if ((prop = node.property ("visible-track-count"))) {
2217 set_visible_track_count (PBD::atoi (prop->value()));
2220 if ((prop = node.property ("snap-to"))) {
2221 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2224 if ((prop = node.property ("snap-mode"))) {
2225 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2228 if ((prop = node.property ("internal-snap-to"))) {
2229 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2232 if ((prop = node.property ("internal-snap-mode"))) {
2233 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2236 if ((prop = node.property ("pre-internal-snap-to"))) {
2237 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2240 if ((prop = node.property ("pre-internal-snap-mode"))) {
2241 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2244 if ((prop = node.property ("mouse-mode"))) {
2245 MouseMode m = str2mousemode(prop->value());
2246 set_mouse_mode (m, true);
2248 set_mouse_mode (MouseObject, true);
2251 if ((prop = node.property ("left-frame")) != 0) {
2253 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2257 reset_x_origin (pos);
2261 if ((prop = node.property ("y-origin")) != 0) {
2262 reset_y_origin (atof (prop->value ()));
2265 if ((prop = node.property ("join-object-range"))) {
2266 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2267 bool yn = string_is_affirmative (prop->value());
2269 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2270 tact->set_active (!yn);
2271 tact->set_active (yn);
2273 set_mouse_mode(mouse_mode, true);
2276 if ((prop = node.property ("edit-point"))) {
2277 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2280 if ((prop = node.property ("show-measures"))) {
2281 bool yn = string_is_affirmative (prop->value());
2282 _show_measures = yn;
2285 if ((prop = node.property ("follow-playhead"))) {
2286 bool yn = string_is_affirmative (prop->value());
2287 set_follow_playhead (yn);
2290 if ((prop = node.property ("stationary-playhead"))) {
2291 bool yn = string_is_affirmative (prop->value());
2292 set_stationary_playhead (yn);
2295 if ((prop = node.property ("region-list-sort-type"))) {
2296 RegionListSortType st;
2297 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2300 if ((prop = node.property ("show-editor-mixer"))) {
2302 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2305 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2306 bool yn = string_is_affirmative (prop->value());
2308 /* do it twice to force the change */
2310 tact->set_active (!yn);
2311 tact->set_active (yn);
2314 if ((prop = node.property ("show-editor-list"))) {
2316 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2319 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2320 bool yn = string_is_affirmative (prop->value());
2322 /* do it twice to force the change */
2324 tact->set_active (!yn);
2325 tact->set_active (yn);
2328 if ((prop = node.property (X_("editor-list-page")))) {
2329 _the_notebook.set_current_page (atoi (prop->value ()));
2332 if ((prop = node.property (X_("show-marker-lines")))) {
2333 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2335 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2336 bool yn = string_is_affirmative (prop->value ());
2338 tact->set_active (!yn);
2339 tact->set_active (yn);
2342 XMLNodeList children = node.children ();
2343 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2344 selection->set_state (**i, Stateful::current_state_version);
2345 _regions->set_state (**i);
2348 if ((prop = node.property ("maximised"))) {
2349 bool yn = string_is_affirmative (prop->value());
2350 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2352 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2353 bool fs = tact && tact->get_active();
2355 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2359 if ((prop = node.property ("nudge-clock-value"))) {
2361 sscanf (prop->value().c_str(), "%" PRId64, &f);
2362 nudge_clock->set (f);
2364 nudge_clock->set_mode (AudioClock::Timecode);
2365 nudge_clock->set (_session->frame_rate() * 5, true);
2370 * Not all properties may have been in XML, but
2371 * those that are linked to a private variable may need changing
2376 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2378 yn = _show_measures;
2379 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2380 /* do it twice to force the change */
2381 tact->set_active (!yn);
2382 tact->set_active (yn);
2385 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2386 yn = _follow_playhead;
2388 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2389 if (tact->get_active() != yn) {
2390 tact->set_active (yn);
2394 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2395 yn = _stationary_playhead;
2397 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2398 if (tact->get_active() != yn) {
2399 tact->set_active (yn);
2408 Editor::get_state ()
2410 XMLNode& node (Tabbable::get_state());
2413 id().print (buf, sizeof (buf));
2414 node.add_property ("id", buf);
2417 // need to save this somehow
2418 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2419 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2420 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2421 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2422 geometry->add_property("edit-vertical-pane-pos", string(buf));
2425 maybe_add_mixer_strip_width (node);
2427 node.add_property ("zoom-focus", enum_2_string (zoom_focus));
2429 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2430 node.add_property ("zoom", buf);
2431 node.add_property ("snap-to", enum_2_string (_snap_type));
2432 node.add_property ("snap-mode", enum_2_string (_snap_mode));
2433 node.add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2434 node.add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2435 node.add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2436 node.add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2437 node.add_property ("edit-point", enum_2_string (_edit_point));
2438 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2439 node.add_property ("visible-track-count", buf);
2441 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2442 node.add_property ("playhead", buf);
2443 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2444 node.add_property ("left-frame", buf);
2445 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2446 node.add_property ("y-origin", buf);
2448 node.add_property ("show-measures", _show_measures ? "yes" : "no");
2449 node.add_property ("maximised", _maximised ? "yes" : "no");
2450 node.add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2451 node.add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2452 node.add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2453 node.add_property ("mouse-mode", enum2str(mouse_mode));
2454 node.add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2456 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2458 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2459 node.add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2462 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2464 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2465 node.add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2468 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2469 node.add_property (X_("editor-list-page"), buf);
2471 if (button_bindings) {
2472 XMLNode* bb = new XMLNode (X_("Buttons"));
2473 button_bindings->save (*bb);
2474 node.add_child_nocopy (*bb);
2477 node.add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2479 node.add_child_nocopy (selection->get_state ());
2480 node.add_child_nocopy (_regions->get_state ());
2482 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2483 node.add_property ("nudge-clock-value", buf);
2488 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2489 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2491 * @return pair: TimeAxisView that y is over, layer index.
2493 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2494 * in stacked or expanded region display mode, otherwise 0.
2496 std::pair<TimeAxisView *, double>
2497 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2499 if (!trackview_relative_offset) {
2500 y -= _trackview_group->canvas_origin().y;
2504 return std::make_pair ( (TimeAxisView *) 0, 0);
2507 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2509 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2516 return std::make_pair ( (TimeAxisView *) 0, 0);
2519 /** Snap a position to the grid, if appropriate, taking into account current
2520 * grid settings and also the state of any snap modifier keys that may be pressed.
2521 * @param start Position to snap.
2522 * @param event Event to get current key modifier information from, or 0.
2525 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2527 if (!_session || !event) {
2531 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2532 if (_snap_mode == SnapOff) {
2533 snap_to_internal (start, direction, for_mark);
2536 if (_snap_mode != SnapOff) {
2537 snap_to_internal (start, direction, for_mark);
2538 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2539 /* SnapOff, but we pressed the snap_delta modifier */
2540 snap_to_internal (start, direction, for_mark);
2546 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2548 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2552 snap_to_internal (start, direction, for_mark, ensure_snap);
2556 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2558 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2559 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2561 switch (_snap_type) {
2562 case SnapToTimecodeFrame:
2563 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2564 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2565 /* start is already on a whole timecode frame, do nothing */
2566 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2567 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2569 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2573 case SnapToTimecodeSeconds:
2574 if (_session->config.get_timecode_offset_negative()) {
2575 start += _session->config.get_timecode_offset ();
2577 start -= _session->config.get_timecode_offset ();
2579 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2580 (start % one_timecode_second == 0)) {
2581 /* start is already on a whole second, do nothing */
2582 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2583 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2585 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2588 if (_session->config.get_timecode_offset_negative()) {
2589 start -= _session->config.get_timecode_offset ();
2591 start += _session->config.get_timecode_offset ();
2595 case SnapToTimecodeMinutes:
2596 if (_session->config.get_timecode_offset_negative()) {
2597 start += _session->config.get_timecode_offset ();
2599 start -= _session->config.get_timecode_offset ();
2601 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2602 (start % one_timecode_minute == 0)) {
2603 /* start is already on a whole minute, do nothing */
2604 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2605 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2607 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2609 if (_session->config.get_timecode_offset_negative()) {
2610 start -= _session->config.get_timecode_offset ();
2612 start += _session->config.get_timecode_offset ();
2616 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2617 abort(); /*NOTREACHED*/
2622 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2624 const framepos_t one_second = _session->frame_rate();
2625 const framepos_t one_minute = _session->frame_rate() * 60;
2626 framepos_t presnap = start;
2630 switch (_snap_type) {
2631 case SnapToTimecodeFrame:
2632 case SnapToTimecodeSeconds:
2633 case SnapToTimecodeMinutes:
2634 return timecode_snap_to_internal (start, direction, for_mark);
2637 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2638 start % (one_second/75) == 0) {
2639 /* start is already on a whole CD frame, do nothing */
2640 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2641 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2643 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2648 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2649 start % one_second == 0) {
2650 /* start is already on a whole second, do nothing */
2651 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2652 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2654 start = (framepos_t) floor ((double) start / one_second) * one_second;
2659 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2660 start % one_minute == 0) {
2661 /* start is already on a whole minute, do nothing */
2662 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2663 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2665 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2670 start = _session->tempo_map().round_to_bar (start, direction);
2674 start = _session->tempo_map().round_to_beat (start, direction);
2677 case SnapToBeatDiv128:
2678 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2680 case SnapToBeatDiv64:
2681 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2683 case SnapToBeatDiv32:
2684 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2686 case SnapToBeatDiv28:
2687 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2689 case SnapToBeatDiv24:
2690 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2692 case SnapToBeatDiv20:
2693 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2695 case SnapToBeatDiv16:
2696 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2698 case SnapToBeatDiv14:
2699 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2701 case SnapToBeatDiv12:
2702 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2704 case SnapToBeatDiv10:
2705 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2707 case SnapToBeatDiv8:
2708 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2710 case SnapToBeatDiv7:
2711 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2713 case SnapToBeatDiv6:
2714 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2716 case SnapToBeatDiv5:
2717 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2719 case SnapToBeatDiv4:
2720 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2722 case SnapToBeatDiv3:
2723 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2725 case SnapToBeatDiv2:
2726 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2734 _session->locations()->marks_either_side (start, before, after);
2736 if (before == max_framepos && after == max_framepos) {
2737 /* No marks to snap to, so just don't snap */
2739 } else if (before == max_framepos) {
2741 } else if (after == max_framepos) {
2743 } else if (before != max_framepos && after != max_framepos) {
2744 /* have before and after */
2745 if ((start - before) < (after - start)) {
2754 case SnapToRegionStart:
2755 case SnapToRegionEnd:
2756 case SnapToRegionSync:
2757 case SnapToRegionBoundary:
2758 if (!region_boundary_cache.empty()) {
2760 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2761 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2763 if (direction > 0) {
2764 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2766 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2769 if (next != region_boundary_cache.begin ()) {
2774 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2775 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2777 if (start > (p + n) / 2) {
2786 switch (_snap_mode) {
2796 if (presnap > start) {
2797 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2801 } else if (presnap < start) {
2802 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2808 /* handled at entry */
2816 Editor::setup_toolbar ()
2818 HBox* mode_box = manage(new HBox);
2819 mode_box->set_border_width (2);
2820 mode_box->set_spacing(2);
2822 HBox* mouse_mode_box = manage (new HBox);
2823 HBox* mouse_mode_hbox = manage (new HBox);
2824 VBox* mouse_mode_vbox = manage (new VBox);
2825 Alignment* mouse_mode_align = manage (new Alignment);
2827 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2828 mouse_mode_size_group->add_widget (smart_mode_button);
2829 mouse_mode_size_group->add_widget (mouse_move_button);
2830 mouse_mode_size_group->add_widget (mouse_cut_button);
2831 mouse_mode_size_group->add_widget (mouse_select_button);
2832 mouse_mode_size_group->add_widget (mouse_timefx_button);
2833 mouse_mode_size_group->add_widget (mouse_audition_button);
2834 mouse_mode_size_group->add_widget (mouse_draw_button);
2835 mouse_mode_size_group->add_widget (mouse_content_button);
2837 mouse_mode_size_group->add_widget (zoom_in_button);
2838 mouse_mode_size_group->add_widget (zoom_out_button);
2839 mouse_mode_size_group->add_widget (zoom_preset_selector);
2840 mouse_mode_size_group->add_widget (zoom_out_full_button);
2841 mouse_mode_size_group->add_widget (zoom_focus_selector);
2843 mouse_mode_size_group->add_widget (tav_shrink_button);
2844 mouse_mode_size_group->add_widget (tav_expand_button);
2845 mouse_mode_size_group->add_widget (visible_tracks_selector);
2847 mouse_mode_size_group->add_widget (snap_type_selector);
2848 mouse_mode_size_group->add_widget (snap_mode_selector);
2850 mouse_mode_size_group->add_widget (edit_point_selector);
2851 mouse_mode_size_group->add_widget (edit_mode_selector);
2853 mouse_mode_size_group->add_widget (*nudge_clock);
2854 mouse_mode_size_group->add_widget (nudge_forward_button);
2855 mouse_mode_size_group->add_widget (nudge_backward_button);
2857 mouse_mode_hbox->set_spacing (2);
2859 if (!ARDOUR::Profile->get_trx()) {
2860 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2863 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2864 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2866 if (!ARDOUR::Profile->get_mixbus()) {
2867 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2870 if (!ARDOUR::Profile->get_trx()) {
2871 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2872 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2873 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2874 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2877 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2879 mouse_mode_align->add (*mouse_mode_vbox);
2880 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2882 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2884 edit_mode_selector.set_name ("mouse mode button");
2886 if (!ARDOUR::Profile->get_trx()) {
2887 mode_box->pack_start (edit_mode_selector, false, false);
2889 mode_box->pack_start (*mouse_mode_box, false, false);
2891 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2892 _mouse_mode_tearoff->set_name ("MouseModeBase");
2893 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2895 if (Profile->get_sae() || Profile->get_mixbus() ) {
2896 _mouse_mode_tearoff->set_can_be_torn_off (false);
2899 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2900 &_mouse_mode_tearoff->tearoff_window()));
2901 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2902 &_mouse_mode_tearoff->tearoff_window(), 1));
2903 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2904 &_mouse_mode_tearoff->tearoff_window()));
2905 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2906 &_mouse_mode_tearoff->tearoff_window(), 1));
2910 _zoom_box.set_spacing (2);
2911 _zoom_box.set_border_width (2);
2915 zoom_preset_selector.set_name ("zoom button");
2916 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2917 zoom_preset_selector.set_size_request (42, -1);
2919 zoom_in_button.set_name ("zoom button");
2920 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
2921 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2922 zoom_in_button.set_related_action (act);
2924 zoom_out_button.set_name ("zoom button");
2925 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
2926 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2927 zoom_out_button.set_related_action (act);
2929 zoom_out_full_button.set_name ("zoom button");
2930 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
2931 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2932 zoom_out_full_button.set_related_action (act);
2934 zoom_focus_selector.set_name ("zoom button");
2936 if (ARDOUR::Profile->get_mixbus()) {
2937 _zoom_box.pack_start (zoom_preset_selector, false, false);
2938 } else if (ARDOUR::Profile->get_trx()) {
2939 mode_box->pack_start (zoom_out_button, false, false);
2940 mode_box->pack_start (zoom_in_button, false, false);
2942 _zoom_box.pack_start (zoom_out_button, false, false);
2943 _zoom_box.pack_start (zoom_in_button, false, false);
2944 _zoom_box.pack_start (zoom_out_full_button, false, false);
2945 _zoom_box.pack_start (zoom_focus_selector, false, false);
2948 /* Track zoom buttons */
2949 visible_tracks_selector.set_name ("zoom button");
2950 if (Profile->get_mixbus()) {
2951 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2952 visible_tracks_selector.set_size_request (42, -1);
2954 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2957 tav_expand_button.set_name ("zoom button");
2958 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
2959 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2960 tav_expand_button.set_related_action (act);
2962 tav_shrink_button.set_name ("zoom button");
2963 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
2964 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2965 tav_shrink_button.set_related_action (act);
2967 if (ARDOUR::Profile->get_mixbus()) {
2968 _zoom_box.pack_start (visible_tracks_selector);
2969 } else if (ARDOUR::Profile->get_trx()) {
2970 _zoom_box.pack_start (tav_shrink_button);
2971 _zoom_box.pack_start (tav_expand_button);
2973 _zoom_box.pack_start (visible_tracks_selector);
2974 _zoom_box.pack_start (tav_shrink_button);
2975 _zoom_box.pack_start (tav_expand_button);
2978 if (!ARDOUR::Profile->get_trx()) {
2979 _zoom_tearoff = manage (new TearOff (_zoom_box));
2981 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2982 &_zoom_tearoff->tearoff_window()));
2983 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2984 &_zoom_tearoff->tearoff_window(), 0));
2985 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2986 &_zoom_tearoff->tearoff_window()));
2987 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2988 &_zoom_tearoff->tearoff_window(), 0));
2991 if (Profile->get_sae() || Profile->get_mixbus() ) {
2992 _zoom_tearoff->set_can_be_torn_off (false);
2995 snap_box.set_spacing (2);
2996 snap_box.set_border_width (2);
2998 snap_type_selector.set_name ("mouse mode button");
3000 snap_mode_selector.set_name ("mouse mode button");
3002 edit_point_selector.set_name ("mouse mode button");
3004 snap_box.pack_start (snap_mode_selector, false, false);
3005 snap_box.pack_start (snap_type_selector, false, false);
3006 snap_box.pack_start (edit_point_selector, false, false);
3010 HBox *nudge_box = manage (new HBox);
3011 nudge_box->set_spacing (2);
3012 nudge_box->set_border_width (2);
3014 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3015 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3017 nudge_box->pack_start (nudge_backward_button, false, false);
3018 nudge_box->pack_start (nudge_forward_button, false, false);
3019 nudge_box->pack_start (*nudge_clock, false, false);
3022 /* Pack everything in... */
3024 HBox* hbox = manage (new HBox);
3025 hbox->set_spacing(2);
3027 _tools_tearoff = manage (new TearOff (*hbox));
3028 _tools_tearoff->set_name ("MouseModeBase");
3029 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3031 if (Profile->get_sae() || Profile->get_mixbus()) {
3032 _tools_tearoff->set_can_be_torn_off (false);
3035 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3036 &_tools_tearoff->tearoff_window()));
3037 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3038 &_tools_tearoff->tearoff_window(), 0));
3039 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3040 &_tools_tearoff->tearoff_window()));
3041 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3042 &_tools_tearoff->tearoff_window(), 0));
3044 toolbar_hbox.set_spacing (2);
3045 toolbar_hbox.set_border_width (1);
3047 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3048 if (!ARDOUR::Profile->get_trx()) {
3049 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3050 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3053 if (!ARDOUR::Profile->get_trx()) {
3054 hbox->pack_start (snap_box, false, false);
3055 hbox->pack_start (*nudge_box, false, false);
3057 hbox->pack_start (panic_box, false, false);
3061 toolbar_base.set_name ("ToolBarBase");
3062 toolbar_base.add (toolbar_hbox);
3064 _toolbar_viewport.add (toolbar_base);
3065 /* stick to the required height but allow width to vary if there's not enough room */
3066 _toolbar_viewport.set_size_request (1, -1);
3068 toolbar_frame.set_shadow_type (SHADOW_OUT);
3069 toolbar_frame.set_name ("BaseFrame");
3070 toolbar_frame.add (_toolbar_viewport);
3074 Editor::build_edit_point_menu ()
3076 using namespace Menu_Helpers;
3078 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3079 if(!Profile->get_mixbus())
3080 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3081 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3083 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3087 Editor::build_edit_mode_menu ()
3089 using namespace Menu_Helpers;
3091 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3092 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3093 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3094 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3096 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3100 Editor::build_snap_mode_menu ()
3102 using namespace Menu_Helpers;
3104 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3105 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3106 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3108 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3112 Editor::build_snap_type_menu ()
3114 using namespace Menu_Helpers;
3116 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3117 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3118 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3119 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3120 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3121 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3122 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3123 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3124 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3125 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3126 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3127 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3128 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3129 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3130 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3131 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3132 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3133 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3134 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3135 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3136 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3137 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3138 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3139 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3140 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3141 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3142 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3143 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3144 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3145 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3147 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3152 Editor::setup_tooltips ()
3154 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3155 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3156 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3157 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3158 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3159 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3160 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3161 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3162 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3163 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3164 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3165 set_tooltip (zoom_in_button, _("Zoom In"));
3166 set_tooltip (zoom_out_button, _("Zoom Out"));
3167 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3168 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3169 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3170 set_tooltip (tav_expand_button, _("Expand Tracks"));
3171 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3172 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3173 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3174 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3175 set_tooltip (edit_point_selector, _("Edit Point"));
3176 set_tooltip (edit_mode_selector, _("Edit Mode"));
3177 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3181 Editor::convert_drop_to_paths (
3182 vector<string>& paths,
3183 const RefPtr<Gdk::DragContext>& /*context*/,
3186 const SelectionData& data,
3190 if (_session == 0) {
3194 vector<string> uris = data.get_uris();
3198 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3199 are actually URI lists. So do it by hand.
3202 if (data.get_target() != "text/plain") {
3206 /* Parse the "uri-list" format that Nautilus provides,
3207 where each pathname is delimited by \r\n.
3209 THERE MAY BE NO NULL TERMINATING CHAR!!!
3212 string txt = data.get_text();
3216 p = (char *) malloc (txt.length() + 1);
3217 txt.copy (p, txt.length(), 0);
3218 p[txt.length()] = '\0';
3224 while (g_ascii_isspace (*p))
3228 while (*q && (*q != '\n') && (*q != '\r')) {
3235 while (q > p && g_ascii_isspace (*q))
3240 uris.push_back (string (p, q - p + 1));
3244 p = strchr (p, '\n');
3256 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3257 if ((*i).substr (0,7) == "file://") {
3258 paths.push_back (Glib::filename_from_uri (*i));
3266 Editor::new_tempo_section ()
3271 Editor::map_transport_state ()
3273 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3275 if (_session && _session->transport_stopped()) {
3276 have_pending_keyboard_selection = false;
3279 update_loop_range_view ();
3285 Editor::begin_selection_op_history ()
3287 selection_op_cmd_depth = 0;
3288 selection_op_history_it = 0;
3290 while(!selection_op_history.empty()) {
3291 delete selection_op_history.front();
3292 selection_op_history.pop_front();
3295 selection_undo_action->set_sensitive (false);
3296 selection_redo_action->set_sensitive (false);
3297 selection_op_history.push_front (&_selection_memento->get_state ());
3301 Editor::begin_reversible_selection_op (string name)
3304 //cerr << name << endl;
3305 /* begin/commit pairs can be nested */
3306 selection_op_cmd_depth++;
3311 Editor::commit_reversible_selection_op ()
3314 if (selection_op_cmd_depth == 1) {
3316 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3318 The user has undone some selection ops and then made a new one,
3319 making anything earlier in the list invalid.
3322 list<XMLNode *>::iterator it = selection_op_history.begin();
3323 list<XMLNode *>::iterator e_it = it;
3324 advance (e_it, selection_op_history_it);
3326 for ( ; it != e_it; ++it) {
3329 selection_op_history.erase (selection_op_history.begin(), e_it);
3332 selection_op_history.push_front (&_selection_memento->get_state ());
3333 selection_op_history_it = 0;
3335 selection_undo_action->set_sensitive (true);
3336 selection_redo_action->set_sensitive (false);
3339 if (selection_op_cmd_depth > 0) {
3340 selection_op_cmd_depth--;
3346 Editor::undo_selection_op ()
3349 selection_op_history_it++;
3351 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3352 if (n == selection_op_history_it) {
3353 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3354 selection_redo_action->set_sensitive (true);
3358 /* is there an earlier entry? */
3359 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3360 selection_undo_action->set_sensitive (false);
3366 Editor::redo_selection_op ()
3369 if (selection_op_history_it > 0) {
3370 selection_op_history_it--;
3373 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3374 if (n == selection_op_history_it) {
3375 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3376 selection_undo_action->set_sensitive (true);
3381 if (selection_op_history_it == 0) {
3382 selection_redo_action->set_sensitive (false);
3388 Editor::begin_reversible_command (string name)
3391 before.push_back (&_selection_memento->get_state ());
3392 _session->begin_reversible_command (name);
3397 Editor::begin_reversible_command (GQuark q)
3400 before.push_back (&_selection_memento->get_state ());
3401 _session->begin_reversible_command (q);
3406 Editor::abort_reversible_command ()
3409 while(!before.empty()) {
3410 delete before.front();
3413 _session->abort_reversible_command ();
3418 Editor::commit_reversible_command ()
3421 if (before.size() == 1) {
3422 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3423 redo_action->set_sensitive(false);
3424 undo_action->set_sensitive(true);
3425 begin_selection_op_history ();
3428 if (before.empty()) {
3429 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3434 _session->commit_reversible_command ();
3439 Editor::history_changed ()
3443 if (undo_action && _session) {
3444 if (_session->undo_depth() == 0) {
3445 label = S_("Command|Undo");
3447 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3449 undo_action->property_label() = label;
3452 if (redo_action && _session) {
3453 if (_session->redo_depth() == 0) {
3455 redo_action->set_sensitive (false);
3457 label = string_compose(_("Redo (%1)"), _session->next_redo());
3458 redo_action->set_sensitive (true);
3460 redo_action->property_label() = label;
3465 Editor::duplicate_range (bool with_dialog)
3469 RegionSelection rs = get_regions_from_selection_and_entered ();
3471 if ( selection->time.length() == 0 && rs.empty()) {
3477 ArdourDialog win (_("Duplicate"));
3478 Label label (_("Number of duplications:"));
3479 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3480 SpinButton spinner (adjustment, 0.0, 1);
3483 win.get_vbox()->set_spacing (12);
3484 win.get_vbox()->pack_start (hbox);
3485 hbox.set_border_width (6);
3486 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3488 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3489 place, visually. so do this by hand.
3492 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3493 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3494 spinner.grab_focus();
3500 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3501 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3502 win.set_default_response (RESPONSE_ACCEPT);
3504 spinner.grab_focus ();
3506 switch (win.run ()) {
3507 case RESPONSE_ACCEPT:
3513 times = adjustment.get_value();
3516 if ((current_mouse_mode() == Editing::MouseRange)) {
3517 if (selection->time.length()) {
3518 duplicate_selection (times);
3520 } else if (get_smart_mode()) {
3521 if (selection->time.length()) {
3522 duplicate_selection (times);
3524 duplicate_some_regions (rs, times);
3526 duplicate_some_regions (rs, times);
3531 Editor::set_edit_mode (EditMode m)
3533 Config->set_edit_mode (m);
3537 Editor::cycle_edit_mode ()
3539 switch (Config->get_edit_mode()) {
3541 if (Profile->get_sae()) {
3542 Config->set_edit_mode (Lock);
3544 Config->set_edit_mode (Ripple);
3549 Config->set_edit_mode (Lock);
3552 Config->set_edit_mode (Slide);
3558 Editor::edit_mode_selection_done ( EditMode m )
3560 Config->set_edit_mode ( m );
3564 Editor::snap_type_selection_done (SnapType snaptype)
3566 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3568 ract->set_active ();
3573 Editor::snap_mode_selection_done (SnapMode mode)
3575 RefPtr<RadioAction> ract = snap_mode_action (mode);
3578 ract->set_active (true);
3583 Editor::cycle_edit_point (bool with_marker)
3585 if(Profile->get_mixbus())
3586 with_marker = false;
3588 switch (_edit_point) {
3590 set_edit_point_preference (EditAtPlayhead);
3592 case EditAtPlayhead:
3594 set_edit_point_preference (EditAtSelectedMarker);
3596 set_edit_point_preference (EditAtMouse);
3599 case EditAtSelectedMarker:
3600 set_edit_point_preference (EditAtMouse);
3606 Editor::edit_point_selection_done (EditPoint ep)
3608 set_edit_point_preference ( ep );
3612 Editor::build_zoom_focus_menu ()
3614 using namespace Menu_Helpers;
3616 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3617 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3618 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3619 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3620 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3621 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3623 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3627 Editor::zoom_focus_selection_done ( ZoomFocus f )
3629 RefPtr<RadioAction> ract = zoom_focus_action (f);
3631 ract->set_active ();
3636 Editor::build_track_count_menu ()
3638 using namespace Menu_Helpers;
3640 if (!Profile->get_mixbus()) {
3641 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3642 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3643 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3644 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3645 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3646 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3647 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3648 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3649 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3650 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3651 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3652 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3653 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3655 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3656 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3657 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3658 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3659 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3660 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3661 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3662 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3663 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3664 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3666 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3667 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3668 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3669 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3670 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3671 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3672 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3673 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3674 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3675 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3676 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3681 Editor::set_zoom_preset (int64_t ms)
3684 temporal_zoom_session();
3688 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3689 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3693 Editor::set_visible_track_count (int32_t n)
3695 _visible_track_count = n;
3697 /* if the canvas hasn't really been allocated any size yet, just
3698 record the desired number of visible tracks and return. when canvas
3699 allocation happens, we will get called again and then we can do the
3703 if (_visible_canvas_height <= 1) {
3709 DisplaySuspender ds;
3711 if (_visible_track_count > 0) {
3712 h = trackviews_height() / _visible_track_count;
3713 std::ostringstream s;
3714 s << _visible_track_count;
3716 } else if (_visible_track_count == 0) {
3718 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3719 if ((*i)->marked_for_display()) {
3723 h = trackviews_height() / n;
3726 /* negative value means that the visible track count has
3727 been overridden by explicit track height changes.
3729 visible_tracks_selector.set_text (X_("*"));
3733 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3734 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3737 if (str != visible_tracks_selector.get_text()) {
3738 visible_tracks_selector.set_text (str);
3743 Editor::override_visible_track_count ()
3745 _visible_track_count = -1;
3746 visible_tracks_selector.set_text ( _("*") );
3750 Editor::edit_controls_button_release (GdkEventButton* ev)
3752 if (Keyboard::is_context_menu_event (ev)) {
3753 ARDOUR_UI::instance()->add_route (current_toplevel());
3754 } else if (ev->button == 1) {
3755 selection->clear_tracks ();
3762 Editor::mouse_select_button_release (GdkEventButton* ev)
3764 /* this handles just right-clicks */
3766 if (ev->button != 3) {
3774 Editor::set_zoom_focus (ZoomFocus f)
3776 string str = zoom_focus_strings[(int)f];
3778 if (str != zoom_focus_selector.get_text()) {
3779 zoom_focus_selector.set_text (str);
3782 if (zoom_focus != f) {
3789 Editor::cycle_zoom_focus ()
3791 switch (zoom_focus) {
3793 set_zoom_focus (ZoomFocusRight);
3795 case ZoomFocusRight:
3796 set_zoom_focus (ZoomFocusCenter);
3798 case ZoomFocusCenter:
3799 set_zoom_focus (ZoomFocusPlayhead);
3801 case ZoomFocusPlayhead:
3802 set_zoom_focus (ZoomFocusMouse);
3804 case ZoomFocusMouse:
3805 set_zoom_focus (ZoomFocusEdit);
3808 set_zoom_focus (ZoomFocusLeft);
3814 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3816 /* recover or initialize pane positions. do this here rather than earlier because
3817 we don't want the positions to change the child allocations, which they seem to do.
3823 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3832 XMLNode* geometry = find_named_node (*node, "geometry");
3834 if (which == static_cast<Paned*> (&edit_pane)) {
3836 if (done & Horizontal) {
3840 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3841 _notebook_shrunk = string_is_affirmative (prop->value ());
3844 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3845 /* initial allocation is 90% to canvas, 10% to notebook */
3846 pos = (int) floor (alloc.get_width() * 0.90f);
3847 snprintf (buf, sizeof(buf), "%d", pos);
3849 pos = atoi (prop->value());
3852 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3853 edit_pane.set_position (pos);
3856 done = (Pane) (done | Horizontal);
3858 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3860 if (done & Vertical) {
3864 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3865 /* initial allocation is 90% to canvas, 10% to summary */
3866 pos = (int) floor (alloc.get_height() * 0.90f);
3867 snprintf (buf, sizeof(buf), "%d", pos);
3870 pos = atoi (prop->value());
3873 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3874 editor_summary_pane.set_position (pos);
3877 done = (Pane) (done | Vertical);
3882 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3884 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3885 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3886 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3887 top_hbox.remove (toolbar_frame);
3892 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3894 if (toolbar_frame.get_parent() == 0) {
3895 top_hbox.pack_end (toolbar_frame);
3900 Editor::set_show_measures (bool yn)
3902 if (_show_measures != yn) {
3905 if ((_show_measures = yn) == true) {
3907 tempo_lines->show();
3910 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3911 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3913 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3914 draw_measures (begin, end);
3922 Editor::toggle_follow_playhead ()
3924 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3926 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3927 set_follow_playhead (tact->get_active());
3931 /** @param yn true to follow playhead, otherwise false.
3932 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3935 Editor::set_follow_playhead (bool yn, bool catch_up)
3937 if (_follow_playhead != yn) {
3938 if ((_follow_playhead = yn) == true && catch_up) {
3940 reset_x_origin_to_follow_playhead ();
3947 Editor::toggle_stationary_playhead ()
3949 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3951 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3952 set_stationary_playhead (tact->get_active());
3957 Editor::set_stationary_playhead (bool yn)
3959 if (_stationary_playhead != yn) {
3960 if ((_stationary_playhead = yn) == true) {
3962 // FIXME need a 3.0 equivalent of this 2.X call
3963 // update_current_screen ();
3970 Editor::playlist_selector () const
3972 return *_playlist_selector;
3976 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
3978 if (paste_count == 0) {
3979 /* don't bother calculating an offset that will be zero anyway */
3983 /* calculate basic unsnapped multi-paste offset */
3984 framecnt_t offset = paste_count * duration;
3986 /* snap offset so pos + offset is aligned to the grid */
3987 framepos_t offset_pos = pos + offset;
3988 snap_to(offset_pos, RoundUpMaybe);
3989 offset = offset_pos - pos;
3995 Editor::get_grid_beat_divisions(framepos_t position)
3997 switch (_snap_type) {
3998 case SnapToBeatDiv128: return 128;
3999 case SnapToBeatDiv64: return 64;
4000 case SnapToBeatDiv32: return 32;
4001 case SnapToBeatDiv28: return 28;
4002 case SnapToBeatDiv24: return 24;
4003 case SnapToBeatDiv20: return 20;
4004 case SnapToBeatDiv16: return 16;
4005 case SnapToBeatDiv14: return 14;
4006 case SnapToBeatDiv12: return 12;
4007 case SnapToBeatDiv10: return 10;
4008 case SnapToBeatDiv8: return 8;
4009 case SnapToBeatDiv7: return 7;
4010 case SnapToBeatDiv6: return 6;
4011 case SnapToBeatDiv5: return 5;
4012 case SnapToBeatDiv4: return 4;
4013 case SnapToBeatDiv3: return 3;
4014 case SnapToBeatDiv2: return 2;
4021 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4025 const unsigned divisions = get_grid_beat_divisions(position);
4027 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4030 switch (_snap_type) {
4032 return Evoral::Beats(1.0);
4035 return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
4043 return Evoral::Beats();
4047 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4051 ret = nudge_clock->current_duration (pos);
4052 next = ret + 1; /* XXXX fix me */
4058 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4060 ArdourDialog dialog (_("Playlist Deletion"));
4061 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4062 "If it is kept, its audio files will not be cleaned.\n"
4063 "If it is deleted, audio files used by it alone will be cleaned."),
4066 dialog.set_position (WIN_POS_CENTER);
4067 dialog.get_vbox()->pack_start (label);
4071 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4072 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4073 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4074 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4075 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4077 // by default gtk uses the left most button
4078 keep->grab_focus ();
4080 switch (dialog.run ()) {
4082 /* keep this and all remaining ones */
4087 /* delete this and all others */
4091 case RESPONSE_ACCEPT:
4092 /* delete the playlist */
4096 case RESPONSE_REJECT:
4097 /* keep the playlist */
4109 Editor::audio_region_selection_covers (framepos_t where)
4111 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4112 if ((*a)->region()->covers (where)) {
4121 Editor::prepare_for_cleanup ()
4123 cut_buffer->clear_regions ();
4124 cut_buffer->clear_playlists ();
4126 selection->clear_regions ();
4127 selection->clear_playlists ();
4129 _regions->suspend_redisplay ();
4133 Editor::finish_cleanup ()
4135 _regions->resume_redisplay ();
4139 Editor::transport_loop_location()
4142 return _session->locations()->auto_loop_location();
4149 Editor::transport_punch_location()
4152 return _session->locations()->auto_punch_location();
4159 Editor::control_layout_scroll (GdkEventScroll* ev)
4161 /* Just forward to the normal canvas scroll method. The coordinate
4162 systems are different but since the canvas is always larger than the
4163 track headers, and aligned with the trackview area, this will work.
4165 In the not too distant future this layout is going away anyway and
4166 headers will be on the canvas.
4168 return canvas_scroll_event (ev, false);
4172 Editor::session_state_saved (string)
4175 _snapshots->redisplay ();
4179 Editor::update_tearoff_visibility()
4181 bool visible = UIConfiguration::instance().get_keep_tearoffs();
4182 _mouse_mode_tearoff->set_visible (visible);
4183 _tools_tearoff->set_visible (visible);
4184 if (_zoom_tearoff) {
4185 _zoom_tearoff->set_visible (visible);
4190 Editor::reattach_all_tearoffs ()
4192 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4193 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4194 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4198 Editor::maximise_editing_space ()
4204 current_toplevel()->fullscreen ();
4210 Editor::restore_editing_space ()
4216 current_toplevel()->unfullscreen();
4222 * Make new playlists for a given track and also any others that belong
4223 * to the same active route group with the `select' property.
4228 Editor::new_playlists (TimeAxisView* v)
4230 begin_reversible_command (_("new playlists"));
4231 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4232 _session->playlists->get (playlists);
4233 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4234 commit_reversible_command ();
4238 * Use a copy of the current playlist for a given track and also any others that belong
4239 * to the same active route group with the `select' property.
4244 Editor::copy_playlists (TimeAxisView* v)
4246 begin_reversible_command (_("copy playlists"));
4247 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4248 _session->playlists->get (playlists);
4249 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4250 commit_reversible_command ();
4253 /** Clear the current playlist for a given track and also any others that belong
4254 * to the same active route group with the `select' property.
4259 Editor::clear_playlists (TimeAxisView* v)
4261 begin_reversible_command (_("clear playlists"));
4262 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4263 _session->playlists->get (playlists);
4264 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4265 commit_reversible_command ();
4269 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4271 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4275 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4277 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4281 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4283 atv.clear_playlist ();
4287 Editor::on_key_press_event (GdkEventKey* ev)
4289 return key_press_focus_accelerator_handler (*current_toplevel(), ev);
4293 Editor::on_key_release_event (GdkEventKey* ev)
4296 // return Gtk::Window::on_key_release_event (ev);
4297 // return key_press_focus_accelerator_handler (*this, ev);
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 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4568 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4570 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4571 current_bbt_points_begin, current_bbt_points_end);
4572 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4573 current_bbt_points_begin, current_bbt_points_end);
4574 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4576 update_video_timeline();
4579 if (vc.pending & VisualChange::TimeOrigin) {
4580 set_horizontal_position (vc.time_origin / samples_per_pixel);
4583 if (vc.pending & VisualChange::YOrigin) {
4584 vertical_adjustment.set_value (vc.y_origin);
4587 if (last_time_origin == horizontal_position ()) {
4588 /* changed signal not emitted */
4589 update_fixed_rulers ();
4590 redisplay_tempo (true);
4593 if (!(vc.pending & VisualChange::ZoomLevel)) {
4594 update_video_timeline();
4597 _summary->set_overlays_dirty ();
4600 struct EditorOrderTimeAxisSorter {
4601 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4602 return a->order () < b->order ();
4607 Editor::sort_track_selection (TrackViewList& sel)
4609 EditorOrderTimeAxisSorter cmp;
4614 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4617 framepos_t where = 0;
4618 EditPoint ep = _edit_point;
4620 if (Profile->get_mixbus())
4621 if (ep == EditAtSelectedMarker)
4622 ep = EditAtPlayhead;
4624 if (from_outside_canvas && (ep == EditAtMouse)) {
4625 ep = EditAtPlayhead;
4626 } else if (from_context_menu && (ep == EditAtMouse)) {
4627 return canvas_event_sample (&context_click_event, 0, 0);
4630 if (entered_marker) {
4631 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4632 return entered_marker->position();
4635 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4636 ep = EditAtSelectedMarker;
4639 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4640 ep = EditAtPlayhead;
4644 case EditAtPlayhead:
4645 if (_dragging_playhead) {
4646 where = *_control_scroll_target;
4648 where = _session->audible_frame();
4650 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4653 case EditAtSelectedMarker:
4654 if (!selection->markers.empty()) {
4656 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4659 where = loc->start();
4663 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4671 if (!mouse_frame (where, ignored)) {
4672 /* XXX not right but what can we do ? */
4676 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4684 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4686 if (!_session) return;
4688 begin_reversible_command (cmd);
4692 if ((tll = transport_loop_location()) == 0) {
4693 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4694 XMLNode &before = _session->locations()->get_state();
4695 _session->locations()->add (loc, true);
4696 _session->set_auto_loop_location (loc);
4697 XMLNode &after = _session->locations()->get_state();
4698 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4700 XMLNode &before = tll->get_state();
4701 tll->set_hidden (false, this);
4702 tll->set (start, end);
4703 XMLNode &after = tll->get_state();
4704 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4707 commit_reversible_command ();
4711 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4713 if (!_session) return;
4715 begin_reversible_command (cmd);
4719 if ((tpl = transport_punch_location()) == 0) {
4720 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4721 XMLNode &before = _session->locations()->get_state();
4722 _session->locations()->add (loc, true);
4723 _session->set_auto_punch_location (loc);
4724 XMLNode &after = _session->locations()->get_state();
4725 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4727 XMLNode &before = tpl->get_state();
4728 tpl->set_hidden (false, this);
4729 tpl->set (start, end);
4730 XMLNode &after = tpl->get_state();
4731 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4734 commit_reversible_command ();
4737 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4738 * @param rs List to which found regions are added.
4739 * @param where Time to look at.
4740 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4743 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4745 const TrackViewList* tracks;
4748 tracks = &track_views;
4753 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4755 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4758 boost::shared_ptr<Track> tr;
4759 boost::shared_ptr<Playlist> pl;
4761 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4763 boost::shared_ptr<RegionList> regions = pl->regions_at (
4764 (framepos_t) floor ( (double) where * tr->speed()));
4766 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4767 RegionView* rv = rtv->view()->find_view (*i);
4778 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4780 const TrackViewList* tracks;
4783 tracks = &track_views;
4788 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4789 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4791 boost::shared_ptr<Track> tr;
4792 boost::shared_ptr<Playlist> pl;
4794 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4796 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4797 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4799 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4801 RegionView* rv = rtv->view()->find_view (*i);
4812 /** Get regions using the following method:
4814 * Make a region list using:
4815 * (a) any selected regions
4816 * (b) the intersection of any selected tracks and the edit point(*)
4817 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4819 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4821 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4825 Editor::get_regions_from_selection_and_edit_point ()
4827 RegionSelection regions;
4829 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4830 regions.add (entered_regionview);
4832 regions = selection->regions;
4835 if ( regions.empty() ) {
4836 TrackViewList tracks = selection->tracks;
4838 if (!tracks.empty()) {
4839 /* no region selected or entered, but some selected tracks:
4840 * act on all regions on the selected tracks at the edit point
4842 framepos_t const where = get_preferred_edit_position ();
4843 get_regions_at(regions, where, tracks);
4850 /** Get regions using the following method:
4852 * Make a region list using:
4853 * (a) any selected regions
4854 * (b) the intersection of any selected tracks and the edit point(*)
4855 * (c) if neither exists, then whatever region is under the mouse
4857 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4859 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4862 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4864 RegionSelection regions;
4866 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4867 regions.add (entered_regionview);
4869 regions = selection->regions;
4872 if ( regions.empty() ) {
4873 TrackViewList tracks = selection->tracks;
4875 if (!tracks.empty()) {
4876 /* no region selected or entered, but some selected tracks:
4877 * act on all regions on the selected tracks at the edit point
4879 get_regions_at(regions, pos, tracks);
4886 /** Start with regions that are selected, or the entered regionview if none are selected.
4887 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4888 * of the regions that we started with.
4892 Editor::get_regions_from_selection_and_entered ()
4894 RegionSelection regions = selection->regions;
4896 if (regions.empty() && entered_regionview) {
4897 regions.add (entered_regionview);
4904 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4906 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4907 RouteTimeAxisView* rtav;
4909 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4910 boost::shared_ptr<Playlist> pl;
4911 std::vector<boost::shared_ptr<Region> > results;
4912 boost::shared_ptr<Track> tr;
4914 if ((tr = rtav->track()) == 0) {
4919 if ((pl = (tr->playlist())) != 0) {
4920 boost::shared_ptr<Region> r = pl->region_by_id (id);
4922 RegionView* rv = rtav->view()->find_view (r);
4924 regions.push_back (rv);
4933 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4936 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4937 MidiTimeAxisView* mtav;
4939 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4941 mtav->get_per_region_note_selection (selection);
4948 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4950 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4952 RouteTimeAxisView* tatv;
4954 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4956 boost::shared_ptr<Playlist> pl;
4957 vector<boost::shared_ptr<Region> > results;
4959 boost::shared_ptr<Track> tr;
4961 if ((tr = tatv->track()) == 0) {
4966 if ((pl = (tr->playlist())) != 0) {
4967 if (src_comparison) {
4968 pl->get_source_equivalent_regions (region, results);
4970 pl->get_region_list_equivalent_regions (region, results);
4974 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4975 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4976 regions.push_back (marv);
4985 Editor::show_rhythm_ferret ()
4987 if (rhythm_ferret == 0) {
4988 rhythm_ferret = new RhythmFerret(*this);
4991 rhythm_ferret->set_session (_session);
4992 rhythm_ferret->show ();
4993 rhythm_ferret->present ();
4997 Editor::first_idle ()
4999 MessageDialog* dialog = 0;
5001 if (track_views.size() > 1) {
5002 Timers::TimerSuspender t;
5003 dialog = new MessageDialog (
5004 *current_toplevel(),
5005 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5009 ARDOUR_UI::instance()->flush_pending ();
5012 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5016 // first idle adds route children (automation tracks), so we need to redisplay here
5017 _routes->redisplay ();
5021 if (_session->undo_depth() == 0) {
5022 undo_action->set_sensitive(false);
5024 redo_action->set_sensitive(false);
5025 begin_selection_op_history ();
5031 Editor::_idle_resize (gpointer arg)
5033 return ((Editor*)arg)->idle_resize ();
5037 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5039 if (resize_idle_id < 0) {
5040 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5041 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5042 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5044 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5045 _pending_resize_amount = 0;
5048 /* make a note of the smallest resulting height, so that we can clamp the
5049 lower limit at TimeAxisView::hSmall */
5051 int32_t min_resulting = INT32_MAX;
5053 _pending_resize_amount += h;
5054 _pending_resize_view = view;
5056 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5058 if (selection->tracks.contains (_pending_resize_view)) {
5059 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5060 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5064 if (min_resulting < 0) {
5069 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5070 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5074 /** Handle pending resizing of tracks */
5076 Editor::idle_resize ()
5078 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5080 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5081 selection->tracks.contains (_pending_resize_view)) {
5083 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5084 if (*i != _pending_resize_view) {
5085 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5090 _pending_resize_amount = 0;
5091 _group_tabs->set_dirty ();
5092 resize_idle_id = -1;
5100 ENSURE_GUI_THREAD (*this, &Editor::located);
5103 playhead_cursor->set_position (_session->audible_frame ());
5104 if (_follow_playhead && !_pending_initial_locate) {
5105 reset_x_origin_to_follow_playhead ();
5109 _pending_locate_request = false;
5110 _pending_initial_locate = false;
5114 Editor::region_view_added (RegionView * rv)
5116 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5117 if (rv->region ()->id () == (*pr)) {
5118 selection->add (rv);
5119 selection->regions.pending.erase (pr);
5124 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5126 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5127 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5128 if (rv->region()->id () == (*rnote).first) {
5129 mrv->select_notes ((*rnote).second);
5130 selection->pending_midi_note_selection.erase(rnote);
5136 _summary->set_background_dirty ();
5140 Editor::region_view_removed ()
5142 _summary->set_background_dirty ();
5146 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5148 TrackViewList::const_iterator j = track_views.begin ();
5149 while (j != track_views.end()) {
5150 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5151 if (rtv && rtv->route() == r) {
5162 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5166 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5167 TimeAxisView* tv = axis_view_from_route (*i);
5177 Editor::suspend_route_redisplay ()
5180 _routes->suspend_redisplay();
5185 Editor::resume_route_redisplay ()
5188 _routes->redisplay(); // queue redisplay
5189 _routes->resume_redisplay();
5194 Editor::add_routes (RouteList& routes)
5196 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5198 RouteTimeAxisView *rtv;
5199 list<RouteTimeAxisView*> new_views;
5200 TrackViewList new_selection;
5201 bool from_scratch = (track_views.size() == 0);
5203 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5204 boost::shared_ptr<Route> route = (*x);
5206 if (route->is_auditioner() || route->is_monitor()) {
5210 DataType dt = route->input()->default_type();
5212 if (dt == ARDOUR::DataType::AUDIO) {
5213 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5214 rtv->set_route (route);
5215 } else if (dt == ARDOUR::DataType::MIDI) {
5216 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5217 rtv->set_route (route);
5219 throw unknown_type();
5222 new_views.push_back (rtv);
5223 track_views.push_back (rtv);
5224 new_selection.push_back (rtv);
5226 rtv->effective_gain_display ();
5228 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5229 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5232 if (new_views.size() > 0) {
5233 _routes->routes_added (new_views);
5234 _summary->routes_added (new_views);
5237 if (!from_scratch) {
5238 selection->tracks.clear();
5239 selection->add (new_selection);
5240 begin_selection_op_history();
5243 if (show_editor_mixer_when_tracks_arrive) {
5244 show_editor_mixer (true);
5247 editor_list_button.set_sensitive (true);
5251 Editor::timeaxisview_deleted (TimeAxisView *tv)
5253 if (tv == entered_track) {
5257 if (_session && _session->deletion_in_progress()) {
5258 /* the situation is under control */
5262 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5264 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5266 _routes->route_removed (tv);
5268 TimeAxisView::Children c = tv->get_child_list ();
5269 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5270 if (entered_track == i->get()) {
5275 /* remove it from the list of track views */
5277 TrackViewList::iterator i;
5279 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5280 i = track_views.erase (i);
5283 /* update whatever the current mixer strip is displaying, if revelant */
5285 boost::shared_ptr<Route> route;
5288 route = rtav->route ();
5291 if (current_mixer_strip && current_mixer_strip->route() == route) {
5293 TimeAxisView* next_tv;
5295 if (track_views.empty()) {
5297 } else if (i == track_views.end()) {
5298 next_tv = track_views.front();
5305 set_selected_mixer_strip (*next_tv);
5307 /* make the editor mixer strip go away setting the
5308 * button to inactive (which also unticks the menu option)
5311 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5317 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5319 if (apply_to_selection) {
5320 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5322 TrackSelection::iterator j = i;
5325 hide_track_in_display (*i, false);
5330 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5332 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5333 // this will hide the mixer strip
5334 set_selected_mixer_strip (*tv);
5337 _routes->hide_track_in_display (*tv);
5342 Editor::sync_track_view_list_and_routes ()
5344 track_views = TrackViewList (_routes->views ());
5346 _summary->set_background_dirty();
5347 _group_tabs->set_dirty ();
5349 return false; // do not call again (until needed)
5353 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5355 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5360 /** Find a RouteTimeAxisView by the ID of its route */
5362 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5364 RouteTimeAxisView* v;
5366 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5367 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5368 if(v->route()->id() == id) {
5378 Editor::fit_route_group (RouteGroup *g)
5380 TrackViewList ts = axis_views_from_routes (g->route_list ());
5385 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5387 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5390 _session->cancel_audition ();
5394 if (_session->is_auditioning()) {
5395 _session->cancel_audition ();
5396 if (r == last_audition_region) {
5401 _session->audition_region (r);
5402 last_audition_region = r;
5407 Editor::hide_a_region (boost::shared_ptr<Region> r)
5409 r->set_hidden (true);
5413 Editor::show_a_region (boost::shared_ptr<Region> r)
5415 r->set_hidden (false);
5419 Editor::audition_region_from_region_list ()
5421 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5425 Editor::hide_region_from_region_list ()
5427 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5431 Editor::show_region_in_region_list ()
5433 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5437 Editor::step_edit_status_change (bool yn)
5440 start_step_editing ();
5442 stop_step_editing ();
5447 Editor::start_step_editing ()
5449 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5453 Editor::stop_step_editing ()
5455 step_edit_connection.disconnect ();
5459 Editor::check_step_edit ()
5461 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5462 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5464 mtv->check_step_edit ();
5468 return true; // do it again, till we stop
5472 Editor::scroll_press (Direction dir)
5474 ++_scroll_callbacks;
5476 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5477 /* delay the first auto-repeat */
5483 scroll_backward (1);
5491 scroll_up_one_track ();
5495 scroll_down_one_track ();
5499 /* do hacky auto-repeat */
5500 if (!_scroll_connection.connected ()) {
5502 _scroll_connection = Glib::signal_timeout().connect (
5503 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5506 _scroll_callbacks = 0;
5513 Editor::scroll_release ()
5515 _scroll_connection.disconnect ();
5518 /** Queue a change for the Editor viewport x origin to follow the playhead */
5520 Editor::reset_x_origin_to_follow_playhead ()
5522 framepos_t const frame = playhead_cursor->current_frame ();
5524 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5526 if (_session->transport_speed() < 0) {
5528 if (frame > (current_page_samples() / 2)) {
5529 center_screen (frame-(current_page_samples()/2));
5531 center_screen (current_page_samples()/2);
5538 if (frame < leftmost_frame) {
5540 if (_session->transport_rolling()) {
5541 /* rolling; end up with the playhead at the right of the page */
5542 l = frame - current_page_samples ();
5544 /* not rolling: end up with the playhead 1/4 of the way along the page */
5545 l = frame - current_page_samples() / 4;
5549 if (_session->transport_rolling()) {
5550 /* rolling: end up with the playhead on the left of the page */
5553 /* not rolling: end up with the playhead 3/4 of the way along the page */
5554 l = frame - 3 * current_page_samples() / 4;
5562 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5568 Editor::super_rapid_screen_update ()
5570 if (!_session || !_session->engine().running()) {
5574 /* METERING / MIXER STRIPS */
5576 /* update track meters, if required */
5577 if (contents().is_mapped() && meters_running) {
5578 RouteTimeAxisView* rtv;
5579 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5580 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5581 rtv->fast_update ();
5586 /* and any current mixer strip */
5587 if (current_mixer_strip) {
5588 current_mixer_strip->fast_update ();
5591 /* PLAYHEAD AND VIEWPORT */
5593 framepos_t const frame = _session->audible_frame();
5595 /* There are a few reasons why we might not update the playhead / viewport stuff:
5597 * 1. we don't update things when there's a pending locate request, otherwise
5598 * when the editor requests a locate there is a chance that this method
5599 * will move the playhead before the locate request is processed, causing
5601 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5602 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5605 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5607 last_update_frame = frame;
5609 if (!_dragging_playhead) {
5610 playhead_cursor->set_position (frame);
5613 if (!_stationary_playhead) {
5615 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5616 /* We only do this if we aren't already
5617 handling a visual change (ie if
5618 pending_visual_change.being_handled is
5619 false) so that these requests don't stack
5620 up there are too many of them to handle in
5623 reset_x_origin_to_follow_playhead ();
5628 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5629 framepos_t const frame = playhead_cursor->current_frame ();
5630 double target = ((double)frame - (double)current_page_samples()/2.0);
5631 if (target <= 0.0) {
5634 // compare to EditorCursor::set_position()
5635 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5636 double const new_pos = sample_to_pixel_unrounded (target);
5637 if (rint (new_pos) != rint (old_pos)) {
5638 reset_x_origin (pixel_to_sample (floor (new_pos)));
5649 Editor::session_going_away ()
5651 _have_idled = false;
5653 _session_connections.drop_connections ();
5655 super_rapid_screen_update_connection.disconnect ();
5657 selection->clear ();
5658 cut_buffer->clear ();
5660 clicked_regionview = 0;
5661 clicked_axisview = 0;
5662 clicked_routeview = 0;
5663 entered_regionview = 0;
5665 last_update_frame = 0;
5668 playhead_cursor->hide ();
5670 /* rip everything out of the list displays */
5674 _route_groups->clear ();
5676 /* do this first so that deleting a track doesn't reset cms to null
5677 and thus cause a leak.
5680 if (current_mixer_strip) {
5681 if (current_mixer_strip->get_parent() != 0) {
5682 global_hpacker.remove (*current_mixer_strip);
5684 delete current_mixer_strip;
5685 current_mixer_strip = 0;
5688 /* delete all trackviews */
5690 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5693 track_views.clear ();
5695 nudge_clock->set_session (0);
5697 editor_list_button.set_active(false);
5698 editor_list_button.set_sensitive(false);
5700 /* clear tempo/meter rulers */
5701 remove_metric_marks ();
5703 clear_marker_display ();
5705 stop_step_editing ();
5709 /* get rid of any existing editor mixer strip */
5711 WindowTitle title(Glib::get_application_name());
5712 title += _("Editor");
5714 own_window()->set_title (title.get_string());
5717 SessionHandlePtr::session_going_away ();
5722 Editor::show_editor_list (bool yn)
5725 _the_notebook.show ();
5727 _the_notebook.hide ();
5732 Editor::change_region_layering_order (bool from_context_menu)
5734 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5736 if (!clicked_routeview) {
5737 if (layering_order_editor) {
5738 layering_order_editor->hide ();
5743 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5749 boost::shared_ptr<Playlist> pl = track->playlist();
5755 if (layering_order_editor == 0) {
5756 layering_order_editor = new RegionLayeringOrderEditor (*this);
5759 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5760 layering_order_editor->maybe_present ();
5764 Editor::update_region_layering_order_editor ()
5766 if (layering_order_editor && layering_order_editor->is_visible ()) {
5767 change_region_layering_order (true);
5772 Editor::setup_fade_images ()
5774 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5775 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5776 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5777 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5778 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5780 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5781 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5782 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5783 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5784 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5786 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5787 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5788 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5789 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5790 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5792 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5793 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5794 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5795 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5796 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5800 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5802 Editor::action_menu_item (std::string const & name)
5804 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5807 return *manage (a->create_menu_item ());
5811 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5813 EventBox* b = manage (new EventBox);
5814 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5815 Label* l = manage (new Label (name));
5819 _the_notebook.append_page (widget, *b);
5823 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5825 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5826 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5829 if (ev->type == GDK_2BUTTON_PRESS) {
5831 /* double-click on a notebook tab shrinks or expands the notebook */
5833 if (_notebook_shrunk) {
5834 if (pre_notebook_shrink_pane_width) {
5835 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5837 _notebook_shrunk = false;
5839 pre_notebook_shrink_pane_width = edit_pane.get_position();
5841 /* this expands the LHS of the edit pane to cover the notebook
5842 PAGE but leaves the tabs visible.
5844 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5845 _notebook_shrunk = true;
5853 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5855 using namespace Menu_Helpers;
5857 MenuList& items = _control_point_context_menu.items ();
5860 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5861 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5862 if (!can_remove_control_point (item)) {
5863 items.back().set_sensitive (false);
5866 _control_point_context_menu.popup (event->button.button, event->button.time);
5870 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5872 using namespace Menu_Helpers;
5874 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5879 /* We need to get the selection here and pass it to the operations, since
5880 popping up the menu will cause a region leave event which clears
5881 entered_regionview. */
5883 MidiRegionView& mrv = note->region_view();
5884 const RegionSelection rs = get_regions_from_selection_and_entered ();
5885 const uint32_t sel_size = mrv.selection_size ();
5887 MenuList& items = _note_context_menu.items();
5891 items.push_back(MenuElem(_("Delete"),
5892 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5895 items.push_back(MenuElem(_("Edit..."),
5896 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5897 if (sel_size != 1) {
5898 items.back().set_sensitive (false);
5901 items.push_back(MenuElem(_("Transpose..."),
5902 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
5905 items.push_back(MenuElem(_("Legatize"),
5906 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5908 items.back().set_sensitive (false);
5911 items.push_back(MenuElem(_("Quantize..."),
5912 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5914 items.push_back(MenuElem(_("Remove Overlap"),
5915 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5917 items.back().set_sensitive (false);
5920 items.push_back(MenuElem(_("Transform..."),
5921 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5923 _note_context_menu.popup (event->button.button, event->button.time);
5927 Editor::zoom_vertical_modifier_released()
5929 _stepping_axis_view = 0;
5933 Editor::ui_parameter_changed (string parameter)
5935 if (parameter == "icon-set") {
5936 while (!_cursor_stack.empty()) {
5937 _cursor_stack.pop_back();
5939 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
5940 _cursor_stack.push_back(_cursors->grabber);
5941 } else if (parameter == "draggable-playhead") {
5942 if (_verbose_cursor) {
5943 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
5949 Editor::use_own_window ()
5951 bool new_window = !own_window();
5953 Gtk::Window* win = Tabbable::use_own_window ();
5955 if (win && new_window) {
5956 win->set_name ("EditorWindow");
5957 win->add_accel_group (ActionManager::ui_manager->get_accel_group());
5959 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
5961 // win->signal_realize().connect (*this, &Editor::on_realize);
5962 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
5967 DisplaySuspender ds;
5968 contents().show_all ();
5970 /* XXX: this is a bit unfortunate; it would probably
5971 be nicer if we could just call show () above rather
5972 than needing the show_all ()
5975 /* re-hide stuff if necessary */
5976 editor_list_button_toggled ();
5977 parameter_changed ("show-summary");
5978 parameter_changed ("show-group-tabs");
5979 parameter_changed ("show-zoom-tools");
5981 /* now reset all audio_time_axis heights, because widgets might need
5987 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5988 tv = (static_cast<TimeAxisView*>(*i));
5989 tv->reset_height ();
5992 if (current_mixer_strip) {
5993 current_mixer_strip->hide_things ();
5994 current_mixer_strip->parameter_changed ("mixer-element-visibility");