2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include <gtkmm2ext/keyboard.h>
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
68 #include "ardour/analysis_graph.h"
69 #include "ardour/audio_track.h"
70 #include "ardour/audioengine.h"
71 #include "ardour/audioregion.h"
72 #include "ardour/lmath.h"
73 #include "ardour/location.h"
74 #include "ardour/profile.h"
75 #include "ardour/route.h"
76 #include "ardour/route_group.h"
77 #include "ardour/session_playlists.h"
78 #include "ardour/tempo.h"
79 #include "ardour/utils.h"
80 #include "ardour/vca_manager.h"
81 #include "ardour/vca.h"
83 #include "canvas/debug.h"
84 #include "canvas/text.h"
86 #include "control_protocol/control_protocol.h"
89 #include "analysis_window.h"
90 #include "ardour_spacer.h"
91 #include "audio_clock.h"
92 #include "audio_region_view.h"
93 #include "audio_streamview.h"
94 #include "audio_time_axis.h"
95 #include "automation_time_axis.h"
96 #include "bundle_manager.h"
97 #include "crossfade_edit.h"
101 #include "editor_cursors.h"
102 #include "editor_drag.h"
103 #include "editor_group_tabs.h"
104 #include "editor_locations.h"
105 #include "editor_regions.h"
106 #include "editor_route_groups.h"
107 #include "editor_routes.h"
108 #include "editor_snapshots.h"
109 #include "editor_summary.h"
110 #include "export_report.h"
111 #include "global_port_matrix.h"
112 #include "gui_object.h"
113 #include "gui_thread.h"
114 #include "keyboard.h"
115 #include "keyeditor.h"
116 #include "luainstance.h"
118 #include "midi_region_view.h"
119 #include "midi_time_axis.h"
120 #include "mixer_strip.h"
121 #include "mixer_ui.h"
122 #include "mouse_cursors.h"
123 #include "note_base.h"
124 #include "playlist_selector.h"
125 #include "public_editor.h"
126 #include "quantize_dialog.h"
127 #include "region_layering_order_editor.h"
128 #include "rgb_macros.h"
129 #include "rhythm_ferret.h"
130 #include "route_sorter.h"
131 #include "selection.h"
132 #include "simple_progress_dialog.h"
134 #include "tempo_lines.h"
135 #include "time_axis_view.h"
136 #include "time_info_box.h"
138 #include "tooltips.h"
139 #include "ui_config.h"
141 #include "vca_time_axis.h"
142 #include "verbose_cursor.h"
144 #include "pbd/i18n.h"
147 using namespace ARDOUR;
148 using namespace ARDOUR_UI_UTILS;
151 using namespace Glib;
152 using namespace Gtkmm2ext;
153 using namespace Editing;
155 using PBD::internationalize;
157 using Gtkmm2ext::Keyboard;
159 double Editor::timebar_height = 15.0;
161 static const gchar *_snap_type_strings[] = {
195 static const gchar *_snap_mode_strings[] = {
202 static const gchar *_edit_point_strings[] = {
209 static const gchar *_edit_mode_strings[] = {
217 static const gchar *_zoom_focus_strings[] = {
227 #ifdef USE_RUBBERBAND
228 static const gchar *_rb_opt_strings[] = {
231 N_("Balanced multitimbral mixture"),
232 N_("Unpitched percussion with stable notes"),
233 N_("Crisp monophonic instrumental"),
234 N_("Unpitched solo percussion"),
235 N_("Resample without preserving pitch"),
240 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
243 : PublicEditor (global_hpacker)
244 , editor_mixer_strip_width (Wide)
245 , constructed (false)
246 , _playlist_selector (0)
248 , no_save_visual (false)
250 , samples_per_pixel (2048)
251 , zoom_focus (ZoomFocusPlayhead)
252 , mouse_mode (MouseObject)
253 , pre_internal_snap_type (SnapToBeat)
254 , pre_internal_snap_mode (SnapOff)
255 , internal_snap_type (SnapToBeat)
256 , internal_snap_mode (SnapOff)
257 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
258 , _notebook_shrunk (false)
259 , location_marker_color (0)
260 , location_range_color (0)
261 , location_loop_color (0)
262 , location_punch_color (0)
263 , location_cd_marker_color (0)
265 , _show_marker_lines (false)
266 , clicked_axisview (0)
267 , clicked_routeview (0)
268 , clicked_regionview (0)
269 , clicked_selection (0)
270 , clicked_control_point (0)
271 , button_release_can_deselect (true)
272 , _mouse_changed_selection (false)
273 , region_edit_menu_split_item (0)
274 , region_edit_menu_split_multichannel_item (0)
275 , track_region_edit_playlist_menu (0)
276 , track_edit_playlist_submenu (0)
277 , track_selection_edit_playlist_submenu (0)
278 , _popup_region_menu_item (0)
280 , _track_canvas_viewport (0)
281 , within_track_canvas (false)
282 , _verbose_cursor (0)
286 , range_marker_group (0)
287 , transport_marker_group (0)
288 , cd_marker_group (0)
289 , _time_markers_group (0)
290 , hv_scroll_group (0)
292 , cursor_scroll_group (0)
293 , no_scroll_group (0)
294 , _trackview_group (0)
295 , _drag_motion_group (0)
296 , _canvas_drop_zone (0)
297 , no_ruler_shown_update (false)
298 , ruler_grabbed_widget (0)
300 , minsec_mark_interval (0)
301 , minsec_mark_modulo (0)
303 , timecode_mark_modulo (0)
304 , timecode_nmarks (0)
305 , _samples_ruler_interval (0)
308 , bbt_bar_helper_on (0)
309 , bbt_accent_modulo (0)
314 , visible_timebars (0)
315 , editor_ruler_menu (0)
319 , range_marker_bar (0)
320 , transport_marker_bar (0)
322 , minsec_label (_("Mins:Secs"))
323 , bbt_label (_("Bars:Beats"))
324 , timecode_label (_("Timecode"))
325 , samples_label (_("Samples"))
326 , tempo_label (_("Tempo"))
327 , meter_label (_("Meter"))
328 , mark_label (_("Location Markers"))
329 , range_mark_label (_("Range Markers"))
330 , transport_mark_label (_("Loop/Punch Ranges"))
331 , cd_mark_label (_("CD Markers"))
332 , videotl_label (_("Video Timeline"))
334 , playhead_cursor (0)
335 , edit_packer (4, 4, true)
336 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
337 , horizontal_adjustment (0.0, 0.0, 1e16)
338 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
339 , controls_layout (unused_adjustment, vertical_adjustment)
340 , _scroll_callbacks (0)
341 , _visible_canvas_width (0)
342 , _visible_canvas_height (0)
343 , _full_canvas_height (0)
344 , edit_controls_left_menu (0)
345 , edit_controls_right_menu (0)
346 , last_update_frame (0)
347 , cut_buffer_start (0)
348 , cut_buffer_length (0)
349 , button_bindings (0)
353 , current_interthread_info (0)
354 , analysis_window (0)
355 , select_new_marker (false)
357 , scrubbing_direction (0)
358 , scrub_reversals (0)
359 , scrub_reverse_distance (0)
360 , have_pending_keyboard_selection (false)
361 , pending_keyboard_selection_start (0)
362 , _snap_type (SnapToBeat)
363 , _snap_mode (SnapOff)
364 , snap_threshold (5.0)
365 , ignore_gui_changes (false)
366 , _drags (new DragManager (this))
368 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
369 , _dragging_playhead (false)
370 , _dragging_edit_point (false)
371 , _show_measures (true)
372 , _follow_playhead (true)
373 , _stationary_playhead (false)
376 , global_rect_group (0)
377 , time_line_group (0)
378 , tempo_marker_menu (0)
379 , meter_marker_menu (0)
381 , range_marker_menu (0)
382 , transport_marker_menu (0)
383 , new_transport_marker_menu (0)
385 , marker_menu_item (0)
386 , bbt_beat_subdivision (4)
387 , _visible_track_count (-1)
388 , toolbar_selection_clock_table (2,3)
389 , automation_mode_button (_("mode"))
390 , selection (new Selection (this))
391 , cut_buffer (new Selection (this))
392 , _selection_memento (new SelectionMemento())
393 , _all_region_actions_sensitized (false)
394 , _ignore_region_action (false)
395 , _last_region_menu_was_main (false)
396 , cd_marker_bar_drag_rect (0)
397 , range_bar_drag_rect (0)
398 , transport_bar_drag_rect (0)
399 , transport_bar_range_rect (0)
400 , transport_bar_preroll_rect (0)
401 , transport_bar_postroll_rect (0)
402 , transport_loop_range_rect (0)
403 , transport_punch_range_rect (0)
404 , transport_punchin_line (0)
405 , transport_punchout_line (0)
406 , transport_preroll_rect (0)
407 , transport_postroll_rect (0)
409 , rubberband_rect (0)
415 , autoscroll_horizontal_allowed (false)
416 , autoscroll_vertical_allowed (false)
418 , autoscroll_widget (0)
419 , show_gain_after_trim (false)
420 , selection_op_cmd_depth (0)
421 , selection_op_history_it (0)
422 , no_save_instant (false)
424 , current_mixer_strip (0)
425 , show_editor_mixer_when_tracks_arrive (false)
426 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
427 , current_stepping_trackview (0)
428 , last_track_height_step_timestamp (0)
430 , entered_regionview (0)
431 , clear_entered_track (false)
432 , _edit_point (EditAtMouse)
433 , meters_running (false)
435 , _have_idled (false)
436 , resize_idle_id (-1)
437 , _pending_resize_amount (0)
438 , _pending_resize_view (0)
439 , _pending_locate_request (false)
440 , _pending_initial_locate (false)
444 , layering_order_editor (0)
445 , _last_cut_copy_source_track (0)
446 , _region_selection_change_updates_region_list (true)
448 , _following_mixer_selection (false)
449 , _control_point_toggled_on_press (false)
450 , _stepping_axis_view (0)
451 , quantize_dialog (0)
452 , _main_menu_disabler (0)
453 , myactions (X_("editor"))
455 /* we are a singleton */
457 PublicEditor::_instance = this;
461 last_event_time.tv_sec = 0;
462 last_event_time.tv_usec = 0;
464 selection_op_history.clear();
467 snap_type_strings = I18N (_snap_type_strings);
468 snap_mode_strings = I18N (_snap_mode_strings);
469 zoom_focus_strings = I18N (_zoom_focus_strings);
470 edit_mode_strings = I18N (_edit_mode_strings);
471 edit_point_strings = I18N (_edit_point_strings);
472 #ifdef USE_RUBBERBAND
473 rb_opt_strings = I18N (_rb_opt_strings);
477 build_edit_mode_menu();
478 build_zoom_focus_menu();
479 build_track_count_menu();
480 build_snap_mode_menu();
481 build_snap_type_menu();
482 build_edit_point_menu();
484 location_marker_color = UIConfiguration::instance().color ("location marker");
485 location_range_color = UIConfiguration::instance().color ("location range");
486 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
487 location_loop_color = UIConfiguration::instance().color ("location loop");
488 location_punch_color = UIConfiguration::instance().color ("location punch");
490 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
492 TimeAxisView::setup_sizes ();
493 ArdourMarker::setup_sizes (timebar_height);
494 TempoCurve::setup_sizes (timebar_height);
496 bbt_label.set_name ("EditorRulerLabel");
497 bbt_label.set_size_request (-1, (int)timebar_height);
498 bbt_label.set_alignment (1.0, 0.5);
499 bbt_label.set_padding (5,0);
501 bbt_label.set_no_show_all();
502 minsec_label.set_name ("EditorRulerLabel");
503 minsec_label.set_size_request (-1, (int)timebar_height);
504 minsec_label.set_alignment (1.0, 0.5);
505 minsec_label.set_padding (5,0);
506 minsec_label.hide ();
507 minsec_label.set_no_show_all();
508 timecode_label.set_name ("EditorRulerLabel");
509 timecode_label.set_size_request (-1, (int)timebar_height);
510 timecode_label.set_alignment (1.0, 0.5);
511 timecode_label.set_padding (5,0);
512 timecode_label.hide ();
513 timecode_label.set_no_show_all();
514 samples_label.set_name ("EditorRulerLabel");
515 samples_label.set_size_request (-1, (int)timebar_height);
516 samples_label.set_alignment (1.0, 0.5);
517 samples_label.set_padding (5,0);
518 samples_label.hide ();
519 samples_label.set_no_show_all();
521 tempo_label.set_name ("EditorRulerLabel");
522 tempo_label.set_size_request (-1, (int)timebar_height);
523 tempo_label.set_alignment (1.0, 0.5);
524 tempo_label.set_padding (5,0);
526 tempo_label.set_no_show_all();
528 meter_label.set_name ("EditorRulerLabel");
529 meter_label.set_size_request (-1, (int)timebar_height);
530 meter_label.set_alignment (1.0, 0.5);
531 meter_label.set_padding (5,0);
533 meter_label.set_no_show_all();
535 if (Profile->get_trx()) {
536 mark_label.set_text (_("Markers"));
538 mark_label.set_name ("EditorRulerLabel");
539 mark_label.set_size_request (-1, (int)timebar_height);
540 mark_label.set_alignment (1.0, 0.5);
541 mark_label.set_padding (5,0);
543 mark_label.set_no_show_all();
545 cd_mark_label.set_name ("EditorRulerLabel");
546 cd_mark_label.set_size_request (-1, (int)timebar_height);
547 cd_mark_label.set_alignment (1.0, 0.5);
548 cd_mark_label.set_padding (5,0);
549 cd_mark_label.hide();
550 cd_mark_label.set_no_show_all();
552 videotl_bar_height = 4;
553 videotl_label.set_name ("EditorRulerLabel");
554 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
555 videotl_label.set_alignment (1.0, 0.5);
556 videotl_label.set_padding (5,0);
557 videotl_label.hide();
558 videotl_label.set_no_show_all();
560 range_mark_label.set_name ("EditorRulerLabel");
561 range_mark_label.set_size_request (-1, (int)timebar_height);
562 range_mark_label.set_alignment (1.0, 0.5);
563 range_mark_label.set_padding (5,0);
564 range_mark_label.hide();
565 range_mark_label.set_no_show_all();
567 transport_mark_label.set_name ("EditorRulerLabel");
568 transport_mark_label.set_size_request (-1, (int)timebar_height);
569 transport_mark_label.set_alignment (1.0, 0.5);
570 transport_mark_label.set_padding (5,0);
571 transport_mark_label.hide();
572 transport_mark_label.set_no_show_all();
574 initialize_canvas ();
576 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
578 _summary = new EditorSummary (this);
580 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
581 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
583 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
585 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
586 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
588 edit_controls_vbox.set_spacing (0);
589 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
590 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
592 HBox* h = manage (new HBox);
593 _group_tabs = new EditorGroupTabs (this);
594 if (!ARDOUR::Profile->get_trx()) {
595 h->pack_start (*_group_tabs, PACK_SHRINK);
597 h->pack_start (edit_controls_vbox);
598 controls_layout.add (*h);
600 controls_layout.set_name ("EditControlsBase");
601 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
602 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
603 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
605 _cursors = new MouseCursors;
606 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
607 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
609 /* Push default cursor to ever-present bottom of cursor stack. */
610 push_canvas_cursor(_cursors->grabber);
612 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
614 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
615 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
616 pad_line_1->set_outline_color (0xFF0000FF);
622 edit_packer.set_col_spacings (0);
623 edit_packer.set_row_spacings (0);
624 edit_packer.set_homogeneous (false);
625 edit_packer.set_border_width (0);
626 edit_packer.set_name ("EditorWindow");
628 time_bars_event_box.add (time_bars_vbox);
629 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
630 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
632 /* labels for the time bars */
633 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
635 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
637 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
639 bottom_hbox.set_border_width (2);
640 bottom_hbox.set_spacing (3);
642 _route_groups = new EditorRouteGroups (this);
643 _routes = new EditorRoutes (this);
644 _regions = new EditorRegions (this);
645 _snapshots = new EditorSnapshots (this);
646 _locations = new EditorLocations (this);
647 _time_info_box = new TimeInfoBox (true);
649 /* these are static location signals */
651 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
652 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
653 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
655 add_notebook_page (_("Regions"), _regions->widget ());
656 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
657 add_notebook_page (_("Snapshots"), _snapshots->widget ());
658 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
659 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
661 _the_notebook.set_show_tabs (true);
662 _the_notebook.set_scrollable (true);
663 _the_notebook.popup_disable ();
664 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
665 _the_notebook.show_all ();
667 _notebook_shrunk = false;
670 /* Pick up some settings we need to cache, early */
672 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
675 if (settings && (prop = settings->property ("notebook-shrunk"))) {
676 _notebook_shrunk = string_is_affirmative (prop->value ());
679 editor_summary_pane.set_check_divider_position (true);
680 editor_summary_pane.add (edit_packer);
682 Button* summary_arrows_left_left = manage (new Button);
683 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
684 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
685 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
687 Button* summary_arrows_left_right = manage (new Button);
688 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
689 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
690 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
692 VBox* summary_arrows_left = manage (new VBox);
693 summary_arrows_left->pack_start (*summary_arrows_left_left);
694 summary_arrows_left->pack_start (*summary_arrows_left_right);
696 Button* summary_arrows_right_up = manage (new Button);
697 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
698 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
699 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
701 Button* summary_arrows_right_down = manage (new Button);
702 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
703 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
704 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
706 VBox* summary_arrows_right = manage (new VBox);
707 summary_arrows_right->pack_start (*summary_arrows_right_up);
708 summary_arrows_right->pack_start (*summary_arrows_right_down);
710 Frame* summary_frame = manage (new Frame);
711 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
713 summary_frame->add (*_summary);
714 summary_frame->show ();
716 _summary_hbox.pack_start (*summary_arrows_left, false, false);
717 _summary_hbox.pack_start (*summary_frame, true, true);
718 _summary_hbox.pack_start (*summary_arrows_right, false, false);
720 if (!ARDOUR::Profile->get_trx()) {
721 editor_summary_pane.add (_summary_hbox);
724 edit_pane.set_check_divider_position (true);
725 edit_pane.add (editor_summary_pane);
726 if (!ARDOUR::Profile->get_trx()) {
727 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
728 _editor_list_vbox.pack_start (_the_notebook);
729 edit_pane.add (_editor_list_vbox);
730 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
733 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
734 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
741 if (!settings || ((prop = settings->property ("edit-horizontal-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
742 /* initial allocation is 90% to canvas, 10% to notebook */
743 edit_pane.set_divider (0, 0.90);
745 edit_pane.set_divider (0, fract);
748 if (!settings || ((prop = settings->property ("edit-vertical-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
749 /* initial allocation is 90% to canvas, 10% to summary */
750 editor_summary_pane.set_divider (0, 0.90);
753 editor_summary_pane.set_divider (0, fract);
757 global_vpacker.set_spacing (2);
758 global_vpacker.set_border_width (0);
760 //the next three EventBoxes provide the ability for their child widgets to have a background color. That is all.
762 Gtk::EventBox* ebox = manage (new Gtk::EventBox); //a themeable box
763 ebox->set_name("EditorWindow");
764 ebox->add (toolbar_hbox);
766 Gtk::EventBox* epane_box = manage (new Gtk::EventBox); //a themeable box
767 epane_box->set_name("EditorWindow");
768 epane_box->add (edit_pane);
770 Gtk::EventBox* epane_box2 = manage (new Gtk::EventBox); //a themeable box
771 epane_box2->set_name("EditorWindow");
772 epane_box2->add (global_vpacker);
774 global_vpacker.pack_start (*ebox, false, false);
775 global_vpacker.pack_start (*epane_box, true, true);
776 global_hpacker.pack_start (*epane_box2, true, true);
778 /* need to show the "contents" widget so that notebook will show if tab is switched to
781 global_hpacker.show ();
783 /* register actions now so that set_state() can find them and set toggles/checks etc */
790 _playlist_selector = new PlaylistSelector();
791 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
793 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
797 nudge_forward_button.set_name ("nudge button");
798 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
800 nudge_backward_button.set_name ("nudge button");
801 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
803 fade_context_menu.set_name ("ArdourContextMenu");
805 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
807 /* allow external control surfaces/protocols to do various things */
809 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
810 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
811 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
812 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
813 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
814 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
815 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
816 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
817 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
818 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
819 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
820 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
821 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
822 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
824 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
825 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
826 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
827 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
828 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
830 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
834 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
836 /* problematic: has to return a value and thus cannot be x-thread */
838 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
840 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
841 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
843 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
845 _ignore_region_action = false;
846 _last_region_menu_was_main = false;
847 _popup_region_menu_item = 0;
849 _show_marker_lines = false;
851 /* Button bindings */
853 button_bindings = new Bindings ("editor-mouse");
855 XMLNode* node = button_settings();
857 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
858 button_bindings->load_operation (**i);
864 /* grab current parameter state */
865 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
866 UIConfiguration::instance().map_parameters (pc);
868 setup_fade_images ();
870 LuaInstance::instance(); // instantiate
871 LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &Editor::set_script_action_name));
878 delete button_bindings;
880 delete _route_groups;
881 delete _track_canvas_viewport;
884 delete _verbose_cursor;
885 delete quantize_dialog;
891 delete _playlist_selector;
892 delete _time_info_box;
894 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
900 Editor::button_settings () const
902 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
903 XMLNode* node = find_named_node (*settings, X_("Buttons"));
906 node = new XMLNode (X_("Buttons"));
913 Editor::get_smart_mode () const
915 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
919 Editor::catch_vanishing_regionview (RegionView *rv)
921 /* note: the selection will take care of the vanishing
922 audioregionview by itself.
925 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
929 if (clicked_regionview == rv) {
930 clicked_regionview = 0;
933 if (entered_regionview == rv) {
934 set_entered_regionview (0);
937 if (!_all_region_actions_sensitized) {
938 sensitize_all_region_actions (true);
943 Editor::set_entered_regionview (RegionView* rv)
945 if (rv == entered_regionview) {
949 if (entered_regionview) {
950 entered_regionview->exited ();
953 entered_regionview = rv;
955 if (entered_regionview != 0) {
956 entered_regionview->entered ();
959 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
960 /* This RegionView entry might have changed what region actions
961 are allowed, so sensitize them all in case a key is pressed.
963 sensitize_all_region_actions (true);
968 Editor::set_entered_track (TimeAxisView* tav)
971 entered_track->exited ();
977 entered_track->entered ();
982 Editor::instant_save ()
984 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
989 _session->add_instant_xml(get_state());
991 Config->add_instant_xml(get_state());
996 Editor::control_vertical_zoom_in_all ()
998 tav_zoom_smooth (false, true);
1002 Editor::control_vertical_zoom_out_all ()
1004 tav_zoom_smooth (true, true);
1008 Editor::control_vertical_zoom_in_selected ()
1010 tav_zoom_smooth (false, false);
1014 Editor::control_vertical_zoom_out_selected ()
1016 tav_zoom_smooth (true, false);
1020 Editor::control_view (uint32_t view)
1022 goto_visual_state (view);
1026 Editor::control_unselect ()
1028 selection->clear_tracks ();
1032 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1034 TimeAxisView* tav = axis_view_from_stripable (s);
1038 case Selection::Add:
1039 selection->add (tav);
1041 case Selection::Toggle:
1042 selection->toggle (tav);
1044 case Selection::Extend:
1046 case Selection::Set:
1047 selection->set (tav);
1051 selection->clear_tracks ();
1056 Editor::control_step_tracks_up ()
1058 scroll_tracks_up_line ();
1062 Editor::control_step_tracks_down ()
1064 scroll_tracks_down_line ();
1068 Editor::control_scroll (float fraction)
1070 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1076 double step = fraction * current_page_samples();
1079 _control_scroll_target is an optional<T>
1081 it acts like a pointer to an framepos_t, with
1082 a operator conversion to boolean to check
1083 that it has a value could possibly use
1084 playhead_cursor->current_frame to store the
1085 value and a boolean in the class to know
1086 when it's out of date
1089 if (!_control_scroll_target) {
1090 _control_scroll_target = _session->transport_frame();
1091 _dragging_playhead = true;
1094 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1095 *_control_scroll_target = 0;
1096 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1097 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1099 *_control_scroll_target += (framepos_t) trunc (step);
1102 /* move visuals, we'll catch up with it later */
1104 playhead_cursor->set_position (*_control_scroll_target);
1105 UpdateAllTransportClocks (*_control_scroll_target);
1107 if (*_control_scroll_target > (current_page_samples() / 2)) {
1108 /* try to center PH in window */
1109 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1115 Now we do a timeout to actually bring the session to the right place
1116 according to the playhead. This is to avoid reading disk buffers on every
1117 call to control_scroll, which is driven by ScrollTimeline and therefore
1118 probably by a control surface wheel which can generate lots of events.
1120 /* cancel the existing timeout */
1122 control_scroll_connection.disconnect ();
1124 /* add the next timeout */
1126 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1130 Editor::deferred_control_scroll (framepos_t /*target*/)
1132 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1133 // reset for next stream
1134 _control_scroll_target = boost::none;
1135 _dragging_playhead = false;
1140 Editor::access_action (std::string action_group, std::string action_item)
1146 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1149 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1157 Editor::on_realize ()
1161 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1162 start_lock_event_timing ();
1167 Editor::start_lock_event_timing ()
1169 /* check if we should lock the GUI every 30 seconds */
1171 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1175 Editor::generic_event_handler (GdkEvent* ev)
1178 case GDK_BUTTON_PRESS:
1179 case GDK_BUTTON_RELEASE:
1180 case GDK_MOTION_NOTIFY:
1182 case GDK_KEY_RELEASE:
1183 if (contents().is_mapped()) {
1184 gettimeofday (&last_event_time, 0);
1188 case GDK_LEAVE_NOTIFY:
1189 switch (ev->crossing.detail) {
1190 case GDK_NOTIFY_UNKNOWN:
1191 case GDK_NOTIFY_INFERIOR:
1192 case GDK_NOTIFY_ANCESTOR:
1194 case GDK_NOTIFY_VIRTUAL:
1195 case GDK_NOTIFY_NONLINEAR:
1196 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1197 /* leaving window, so reset focus, thus ending any and
1198 all text entry operations.
1200 ARDOUR_UI::instance()->reset_focus (&contents());
1213 Editor::lock_timeout_callback ()
1215 struct timeval now, delta;
1217 gettimeofday (&now, 0);
1219 timersub (&now, &last_event_time, &delta);
1221 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1223 /* don't call again. Returning false will effectively
1224 disconnect us from the timer callback.
1226 unlock() will call start_lock_event_timing() to get things
1236 Editor::map_position_change (framepos_t frame)
1238 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1240 if (_session == 0) {
1244 if (_follow_playhead) {
1245 center_screen (frame);
1248 playhead_cursor->set_position (frame);
1252 Editor::center_screen (framepos_t frame)
1254 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1256 /* if we're off the page, then scroll.
1259 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1260 center_screen_internal (frame, page);
1265 Editor::center_screen_internal (framepos_t frame, float page)
1270 frame -= (framepos_t) page;
1275 reset_x_origin (frame);
1280 Editor::update_title ()
1282 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1284 if (!own_window()) {
1289 bool dirty = _session->dirty();
1291 string session_name;
1293 if (_session->snap_name() != _session->name()) {
1294 session_name = _session->snap_name();
1296 session_name = _session->name();
1300 session_name = "*" + session_name;
1303 WindowTitle title(session_name);
1304 title += S_("Window|Editor");
1305 title += Glib::get_application_name();
1306 own_window()->set_title (title.get_string());
1308 /* ::session_going_away() will have taken care of it */
1313 Editor::set_session (Session *t)
1315 SessionHandlePtr::set_session (t);
1321 _playlist_selector->set_session (_session);
1322 nudge_clock->set_session (_session);
1323 _summary->set_session (_session);
1324 _group_tabs->set_session (_session);
1325 _route_groups->set_session (_session);
1326 _regions->set_session (_session);
1327 _snapshots->set_session (_session);
1328 _routes->set_session (_session);
1329 _locations->set_session (_session);
1330 _time_info_box->set_session (_session);
1332 if (rhythm_ferret) {
1333 rhythm_ferret->set_session (_session);
1336 if (analysis_window) {
1337 analysis_window->set_session (_session);
1341 sfbrowser->set_session (_session);
1344 compute_fixed_ruler_scale ();
1346 /* Make sure we have auto loop and auto punch ranges */
1348 Location* loc = _session->locations()->auto_loop_location();
1350 loc->set_name (_("Loop"));
1353 loc = _session->locations()->auto_punch_location();
1356 loc->set_name (_("Punch"));
1359 refresh_location_display ();
1361 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1362 the selected Marker; this needs the LocationMarker list to be available.
1364 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1365 set_state (*node, Stateful::loading_state_version);
1367 /* catch up with the playhead */
1369 _session->request_locate (playhead_cursor->current_frame ());
1370 _pending_initial_locate = true;
1374 /* These signals can all be emitted by a non-GUI thread. Therefore the
1375 handlers for them must not attempt to directly interact with the GUI,
1376 but use PBD::Signal<T>::connect() which accepts an event loop
1377 ("context") where the handler will be asked to run.
1380 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1381 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1382 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1383 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1384 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1385 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1386 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1387 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::marker_position_changed, this), gui_context());
1388 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1389 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1390 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1391 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1392 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1393 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1394 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1396 playhead_cursor->show ();
1398 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1399 Config->map_parameters (pc);
1400 _session->config.map_parameters (pc);
1402 restore_ruler_visibility ();
1403 //tempo_map_changed (PropertyChange (0));
1404 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1406 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1407 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1410 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1411 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1414 switch (_snap_type) {
1415 case SnapToRegionStart:
1416 case SnapToRegionEnd:
1417 case SnapToRegionSync:
1418 case SnapToRegionBoundary:
1419 build_region_boundary_cache ();
1426 /* catch up on selection of stripables (other selection state is lost
1427 * when a session is closed
1432 _session->get_stripables (sl);
1433 for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
1434 if ((*s)->presentation_info().selected()) {
1435 RouteTimeAxisView* rtav = get_route_view_by_route_id ((*s)->id());
1437 tl.push_back (rtav);
1442 selection->set (tl);
1445 /* register for undo history */
1446 _session->register_with_memento_command_factory(id(), this);
1447 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1449 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1451 LuaInstance::instance()->set_session(_session);
1453 start_updating_meters ();
1457 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1459 if (a->get_name() == "RegionMenu") {
1460 /* When the main menu's region menu is opened, we setup the actions so that they look right
1461 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1462 so we resensitize all region actions when the entered regionview or the region selection
1463 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1464 happens after the region context menu is opened. So we set a flag here, too.
1468 sensitize_the_right_region_actions ();
1469 _last_region_menu_was_main = true;
1474 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1476 using namespace Menu_Helpers;
1478 void (Editor::*emf)(FadeShape);
1479 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1482 images = &_xfade_in_images;
1483 emf = &Editor::set_fade_in_shape;
1485 images = &_xfade_out_images;
1486 emf = &Editor::set_fade_out_shape;
1491 _("Linear (for highly correlated material)"),
1492 *(*images)[FadeLinear],
1493 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1497 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1501 _("Constant power"),
1502 *(*images)[FadeConstantPower],
1503 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1506 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1511 *(*images)[FadeSymmetric],
1512 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1516 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1521 *(*images)[FadeSlow],
1522 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1525 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1530 *(*images)[FadeFast],
1531 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1534 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1537 /** Pop up a context menu for when the user clicks on a start crossfade */
1539 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1541 using namespace Menu_Helpers;
1542 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1547 MenuList& items (xfade_in_context_menu.items());
1550 if (arv->audio_region()->fade_in_active()) {
1551 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1553 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1556 items.push_back (SeparatorElem());
1557 fill_xfade_menu (items, true);
1559 xfade_in_context_menu.popup (button, time);
1562 /** Pop up a context menu for when the user clicks on an end crossfade */
1564 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1566 using namespace Menu_Helpers;
1567 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1572 MenuList& items (xfade_out_context_menu.items());
1575 if (arv->audio_region()->fade_out_active()) {
1576 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1578 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1581 items.push_back (SeparatorElem());
1582 fill_xfade_menu (items, false);
1584 xfade_out_context_menu.popup (button, time);
1588 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1590 using namespace Menu_Helpers;
1591 Menu* (Editor::*build_menu_function)();
1594 switch (item_type) {
1596 case RegionViewName:
1597 case RegionViewNameHighlight:
1598 case LeftFrameHandle:
1599 case RightFrameHandle:
1600 if (with_selection) {
1601 build_menu_function = &Editor::build_track_selection_context_menu;
1603 build_menu_function = &Editor::build_track_region_context_menu;
1608 if (with_selection) {
1609 build_menu_function = &Editor::build_track_selection_context_menu;
1611 build_menu_function = &Editor::build_track_context_menu;
1616 if (clicked_routeview->track()) {
1617 build_menu_function = &Editor::build_track_context_menu;
1619 build_menu_function = &Editor::build_track_bus_context_menu;
1624 /* probably shouldn't happen but if it does, we don't care */
1628 menu = (this->*build_menu_function)();
1629 menu->set_name ("ArdourContextMenu");
1631 /* now handle specific situations */
1633 switch (item_type) {
1635 case RegionViewName:
1636 case RegionViewNameHighlight:
1637 case LeftFrameHandle:
1638 case RightFrameHandle:
1639 if (!with_selection) {
1640 if (region_edit_menu_split_item) {
1641 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1642 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1644 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1647 if (region_edit_menu_split_multichannel_item) {
1648 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1649 region_edit_menu_split_multichannel_item->set_sensitive (true);
1651 region_edit_menu_split_multichannel_item->set_sensitive (false);
1664 /* probably shouldn't happen but if it does, we don't care */
1668 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1670 /* Bounce to disk */
1672 using namespace Menu_Helpers;
1673 MenuList& edit_items = menu->items();
1675 edit_items.push_back (SeparatorElem());
1677 switch (clicked_routeview->audio_track()->freeze_state()) {
1678 case AudioTrack::NoFreeze:
1679 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1682 case AudioTrack::Frozen:
1683 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1686 case AudioTrack::UnFrozen:
1687 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1693 if (item_type == StreamItem && clicked_routeview) {
1694 clicked_routeview->build_underlay_menu(menu);
1697 /* When the region menu is opened, we setup the actions so that they look right
1700 sensitize_the_right_region_actions ();
1701 _last_region_menu_was_main = false;
1703 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1704 menu->popup (button, time);
1708 Editor::build_track_context_menu ()
1710 using namespace Menu_Helpers;
1712 MenuList& edit_items = track_context_menu.items();
1715 add_dstream_context_items (edit_items);
1716 return &track_context_menu;
1720 Editor::build_track_bus_context_menu ()
1722 using namespace Menu_Helpers;
1724 MenuList& edit_items = track_context_menu.items();
1727 add_bus_context_items (edit_items);
1728 return &track_context_menu;
1732 Editor::build_track_region_context_menu ()
1734 using namespace Menu_Helpers;
1735 MenuList& edit_items = track_region_context_menu.items();
1738 /* we've just cleared the track region context menu, so the menu that these
1739 two items were on will have disappeared; stop them dangling.
1741 region_edit_menu_split_item = 0;
1742 region_edit_menu_split_multichannel_item = 0;
1744 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1747 boost::shared_ptr<Track> tr;
1748 boost::shared_ptr<Playlist> pl;
1750 if ((tr = rtv->track())) {
1751 add_region_context_items (edit_items, tr);
1755 add_dstream_context_items (edit_items);
1757 return &track_region_context_menu;
1761 Editor::loudness_analyze_region_selection ()
1766 Selection& s (PublicEditor::instance ().get_selection ());
1767 RegionSelection ars = s.regions;
1768 ARDOUR::AnalysisGraph ag (_session);
1769 framecnt_t total_work = 0;
1771 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1772 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1776 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1779 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1780 total_work += arv->region ()->length ();
1783 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1785 ag.set_total_frames (total_work);
1786 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1789 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1790 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1794 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1798 ag.analyze_region (ar);
1801 if (!ag.canceled ()) {
1802 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1808 Editor::loudness_analyze_range_selection ()
1813 Selection& s (PublicEditor::instance ().get_selection ());
1814 TimeSelection ts = s.time;
1815 ARDOUR::AnalysisGraph ag (_session);
1816 framecnt_t total_work = 0;
1818 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1819 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1823 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1827 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1828 total_work += j->length ();
1832 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1834 ag.set_total_frames (total_work);
1835 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1838 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1839 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1843 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1847 ag.analyze_range (rui->route (), pl, ts);
1850 if (!ag.canceled ()) {
1851 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1857 Editor::spectral_analyze_region_selection ()
1859 if (analysis_window == 0) {
1860 analysis_window = new AnalysisWindow();
1863 analysis_window->set_session(_session);
1865 analysis_window->show_all();
1868 analysis_window->set_regionmode();
1869 analysis_window->analyze();
1871 analysis_window->present();
1875 Editor::spectral_analyze_range_selection()
1877 if (analysis_window == 0) {
1878 analysis_window = new AnalysisWindow();
1881 analysis_window->set_session(_session);
1883 analysis_window->show_all();
1886 analysis_window->set_rangemode();
1887 analysis_window->analyze();
1889 analysis_window->present();
1893 Editor::build_track_selection_context_menu ()
1895 using namespace Menu_Helpers;
1896 MenuList& edit_items = track_selection_context_menu.items();
1897 edit_items.clear ();
1899 add_selection_context_items (edit_items);
1900 // edit_items.push_back (SeparatorElem());
1901 // add_dstream_context_items (edit_items);
1903 return &track_selection_context_menu;
1907 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1909 using namespace Menu_Helpers;
1911 /* OK, stick the region submenu at the top of the list, and then add
1915 RegionSelection rs = get_regions_from_selection_and_entered ();
1917 string::size_type pos = 0;
1918 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1920 /* we have to hack up the region name because "_" has a special
1921 meaning for menu titles.
1924 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1925 menu_item_name.replace (pos, 1, "__");
1929 if (_popup_region_menu_item == 0) {
1930 _popup_region_menu_item = new MenuItem (menu_item_name);
1931 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1932 _popup_region_menu_item->show ();
1934 _popup_region_menu_item->set_label (menu_item_name);
1937 /* No latering allowed in later is higher layering model */
1938 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1939 if (act && Config->get_layer_model() == LaterHigher) {
1940 act->set_sensitive (false);
1942 act->set_sensitive (true);
1945 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1947 edit_items.push_back (*_popup_region_menu_item);
1948 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1949 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1951 edit_items.push_back (SeparatorElem());
1954 /** Add context menu items relevant to selection ranges.
1955 * @param edit_items List to add the items to.
1958 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1960 using namespace Menu_Helpers;
1962 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1963 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1965 edit_items.push_back (SeparatorElem());
1966 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1968 edit_items.push_back (SeparatorElem());
1969 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1970 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1972 edit_items.push_back (SeparatorElem());
1974 edit_items.push_back (
1976 _("Move Range Start to Previous Region Boundary"),
1977 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1981 edit_items.push_back (
1983 _("Move Range Start to Next Region Boundary"),
1984 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1988 edit_items.push_back (
1990 _("Move Range End to Previous Region Boundary"),
1991 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1995 edit_items.push_back (
1997 _("Move Range End to Next Region Boundary"),
1998 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
2002 edit_items.push_back (SeparatorElem());
2003 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
2004 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
2006 edit_items.push_back (SeparatorElem());
2007 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
2009 edit_items.push_back (SeparatorElem());
2010 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
2011 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
2012 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
2014 edit_items.push_back (SeparatorElem());
2015 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
2017 edit_items.push_back (SeparatorElem());
2018 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
2019 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
2021 edit_items.push_back (SeparatorElem());
2022 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
2023 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
2024 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
2025 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
2026 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
2027 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
2028 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2034 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2036 using namespace Menu_Helpers;
2040 Menu *play_menu = manage (new Menu);
2041 MenuList& play_items = play_menu->items();
2042 play_menu->set_name ("ArdourContextMenu");
2044 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2045 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2046 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2047 play_items.push_back (SeparatorElem());
2048 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2050 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2054 Menu *select_menu = manage (new Menu);
2055 MenuList& select_items = select_menu->items();
2056 select_menu->set_name ("ArdourContextMenu");
2058 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2059 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2060 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2061 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2062 select_items.push_back (SeparatorElem());
2063 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2064 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2065 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2066 select_items.push_back (SeparatorElem());
2067 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2068 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2069 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2070 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2071 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2072 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2073 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2075 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2079 Menu *cutnpaste_menu = manage (new Menu);
2080 MenuList& cutnpaste_items = cutnpaste_menu->items();
2081 cutnpaste_menu->set_name ("ArdourContextMenu");
2083 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2084 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2085 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2087 cutnpaste_items.push_back (SeparatorElem());
2089 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2090 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2092 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2094 /* Adding new material */
2096 edit_items.push_back (SeparatorElem());
2097 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2098 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2102 Menu *nudge_menu = manage (new Menu());
2103 MenuList& nudge_items = nudge_menu->items();
2104 nudge_menu->set_name ("ArdourContextMenu");
2106 edit_items.push_back (SeparatorElem());
2107 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2108 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2109 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2110 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2112 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2116 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2118 using namespace Menu_Helpers;
2122 Menu *play_menu = manage (new Menu);
2123 MenuList& play_items = play_menu->items();
2124 play_menu->set_name ("ArdourContextMenu");
2126 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2127 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2128 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2132 Menu *select_menu = manage (new Menu);
2133 MenuList& select_items = select_menu->items();
2134 select_menu->set_name ("ArdourContextMenu");
2136 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2137 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2138 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2139 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2140 select_items.push_back (SeparatorElem());
2141 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2142 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2143 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2144 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2146 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2150 Menu *cutnpaste_menu = manage (new Menu);
2151 MenuList& cutnpaste_items = cutnpaste_menu->items();
2152 cutnpaste_menu->set_name ("ArdourContextMenu");
2154 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2155 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2156 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2158 Menu *nudge_menu = manage (new Menu());
2159 MenuList& nudge_items = nudge_menu->items();
2160 nudge_menu->set_name ("ArdourContextMenu");
2162 edit_items.push_back (SeparatorElem());
2163 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2164 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2165 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2166 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2168 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2172 Editor::snap_type() const
2178 Editor::snap_musical() const
2180 switch (_snap_type) {
2181 case SnapToBeatDiv128:
2182 case SnapToBeatDiv64:
2183 case SnapToBeatDiv32:
2184 case SnapToBeatDiv28:
2185 case SnapToBeatDiv24:
2186 case SnapToBeatDiv20:
2187 case SnapToBeatDiv16:
2188 case SnapToBeatDiv14:
2189 case SnapToBeatDiv12:
2190 case SnapToBeatDiv10:
2191 case SnapToBeatDiv8:
2192 case SnapToBeatDiv7:
2193 case SnapToBeatDiv6:
2194 case SnapToBeatDiv5:
2195 case SnapToBeatDiv4:
2196 case SnapToBeatDiv3:
2197 case SnapToBeatDiv2:
2209 Editor::snap_mode() const
2215 Editor::set_snap_to (SnapType st)
2217 unsigned int snap_ind = (unsigned int)st;
2219 if (internal_editing()) {
2220 internal_snap_type = st;
2222 pre_internal_snap_type = st;
2227 if (snap_ind > snap_type_strings.size() - 1) {
2229 _snap_type = (SnapType)snap_ind;
2232 string str = snap_type_strings[snap_ind];
2234 if (str != snap_type_selector.get_text()) {
2235 snap_type_selector.set_text (str);
2240 switch (_snap_type) {
2241 case SnapToBeatDiv128:
2242 case SnapToBeatDiv64:
2243 case SnapToBeatDiv32:
2244 case SnapToBeatDiv28:
2245 case SnapToBeatDiv24:
2246 case SnapToBeatDiv20:
2247 case SnapToBeatDiv16:
2248 case SnapToBeatDiv14:
2249 case SnapToBeatDiv12:
2250 case SnapToBeatDiv10:
2251 case SnapToBeatDiv8:
2252 case SnapToBeatDiv7:
2253 case SnapToBeatDiv6:
2254 case SnapToBeatDiv5:
2255 case SnapToBeatDiv4:
2256 case SnapToBeatDiv3:
2257 case SnapToBeatDiv2: {
2258 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
2259 update_tempo_based_rulers ();
2263 case SnapToRegionStart:
2264 case SnapToRegionEnd:
2265 case SnapToRegionSync:
2266 case SnapToRegionBoundary:
2267 build_region_boundary_cache ();
2275 redisplay_tempo (false);
2277 SnapChanged (); /* EMIT SIGNAL */
2281 Editor::set_snap_mode (SnapMode mode)
2283 string str = snap_mode_strings[(int)mode];
2285 if (internal_editing()) {
2286 internal_snap_mode = mode;
2288 pre_internal_snap_mode = mode;
2293 if (str != snap_mode_selector.get_text ()) {
2294 snap_mode_selector.set_text (str);
2301 Editor::set_edit_point_preference (EditPoint ep, bool force)
2303 bool changed = (_edit_point != ep);
2306 if (Profile->get_mixbus())
2307 if (ep == EditAtSelectedMarker)
2308 ep = EditAtPlayhead;
2310 string str = edit_point_strings[(int)ep];
2311 if (str != edit_point_selector.get_text ()) {
2312 edit_point_selector.set_text (str);
2315 update_all_enter_cursors();
2317 if (!force && !changed) {
2321 const char* action=NULL;
2323 switch (_edit_point) {
2324 case EditAtPlayhead:
2325 action = "edit-at-playhead";
2327 case EditAtSelectedMarker:
2328 action = "edit-at-marker";
2331 action = "edit-at-mouse";
2335 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2337 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2341 bool in_track_canvas;
2343 if (!mouse_frame (foo, in_track_canvas)) {
2344 in_track_canvas = false;
2347 reset_canvas_action_sensitivity (in_track_canvas);
2353 Editor::set_state (const XMLNode& node, int version)
2355 XMLProperty const * prop;
2357 PBD::Unwinder<bool> nsi (no_save_instant, true);
2360 Tabbable::set_state (node, version);
2362 if (_session && (prop = node.property ("playhead"))) {
2364 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2366 playhead_cursor->set_position (pos);
2368 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2369 playhead_cursor->set_position (0);
2372 playhead_cursor->set_position (0);
2375 if ((prop = node.property ("mixer-width"))) {
2376 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2379 if ((prop = node.property ("zoom-focus"))) {
2380 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2382 zoom_focus_selection_done (zoom_focus);
2385 if ((prop = node.property ("zoom"))) {
2386 /* older versions of ardour used floating point samples_per_pixel */
2387 double f = PBD::atof (prop->value());
2388 reset_zoom (llrintf (f));
2390 reset_zoom (samples_per_pixel);
2393 if ((prop = node.property ("visible-track-count"))) {
2394 set_visible_track_count (PBD::atoi (prop->value()));
2397 if ((prop = node.property ("snap-to"))) {
2398 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2399 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2401 set_snap_to (_snap_type);
2404 if ((prop = node.property ("snap-mode"))) {
2405 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2406 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2407 * snap_mode_selection_done() will only mark an already active item as active
2408 * which does not trigger set_text().
2410 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2412 set_snap_mode (_snap_mode);
2415 if ((prop = node.property ("internal-snap-to"))) {
2416 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2419 if ((prop = node.property ("internal-snap-mode"))) {
2420 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2423 if ((prop = node.property ("pre-internal-snap-to"))) {
2424 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2427 if ((prop = node.property ("pre-internal-snap-mode"))) {
2428 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2431 if ((prop = node.property ("mouse-mode"))) {
2432 MouseMode m = str2mousemode(prop->value());
2433 set_mouse_mode (m, true);
2435 set_mouse_mode (MouseObject, true);
2438 if ((prop = node.property ("left-frame")) != 0) {
2440 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2444 reset_x_origin (pos);
2448 if ((prop = node.property ("y-origin")) != 0) {
2449 reset_y_origin (atof (prop->value ()));
2452 if ((prop = node.property ("join-object-range"))) {
2453 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2454 bool yn = string_is_affirmative (prop->value());
2456 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2457 tact->set_active (!yn);
2458 tact->set_active (yn);
2460 set_mouse_mode(mouse_mode, true);
2463 if ((prop = node.property ("edit-point"))) {
2464 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2466 set_edit_point_preference (_edit_point);
2469 if ((prop = node.property ("show-measures"))) {
2470 bool yn = string_is_affirmative (prop->value());
2471 _show_measures = yn;
2474 if ((prop = node.property ("follow-playhead"))) {
2475 bool yn = string_is_affirmative (prop->value());
2476 set_follow_playhead (yn);
2479 if ((prop = node.property ("stationary-playhead"))) {
2480 bool yn = string_is_affirmative (prop->value());
2481 set_stationary_playhead (yn);
2484 if ((prop = node.property ("region-list-sort-type"))) {
2485 RegionListSortType st;
2486 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2489 if ((prop = node.property ("show-editor-mixer"))) {
2491 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2494 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2495 bool yn = string_is_affirmative (prop->value());
2497 /* do it twice to force the change */
2499 tact->set_active (!yn);
2500 tact->set_active (yn);
2503 if ((prop = node.property ("show-editor-list"))) {
2505 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2508 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2509 bool yn = string_is_affirmative (prop->value());
2511 /* do it twice to force the change */
2513 tact->set_active (!yn);
2514 tact->set_active (yn);
2517 if ((prop = node.property (X_("editor-list-page")))) {
2518 _the_notebook.set_current_page (atoi (prop->value ()));
2521 if ((prop = node.property (X_("show-marker-lines")))) {
2522 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2524 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2525 bool yn = string_is_affirmative (prop->value ());
2527 tact->set_active (!yn);
2528 tact->set_active (yn);
2531 XMLNodeList children = node.children ();
2532 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2533 selection->set_state (**i, Stateful::current_state_version);
2534 _regions->set_state (**i);
2537 if ((prop = node.property ("maximised"))) {
2538 bool yn = string_is_affirmative (prop->value());
2539 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2541 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2542 bool fs = tact && tact->get_active();
2544 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2548 if ((prop = node.property ("nudge-clock-value"))) {
2550 sscanf (prop->value().c_str(), "%" PRId64, &f);
2551 nudge_clock->set (f);
2553 nudge_clock->set_mode (AudioClock::Timecode);
2554 nudge_clock->set (_session->frame_rate() * 5, true);
2559 * Not all properties may have been in XML, but
2560 * those that are linked to a private variable may need changing
2565 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2567 yn = _show_measures;
2568 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2569 /* do it twice to force the change */
2570 tact->set_active (!yn);
2571 tact->set_active (yn);
2574 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2575 yn = _follow_playhead;
2577 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2578 if (tact->get_active() != yn) {
2579 tact->set_active (yn);
2583 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2584 yn = _stationary_playhead;
2586 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2587 if (tact->get_active() != yn) {
2588 tact->set_active (yn);
2593 return LuaInstance::instance()->set_state(node);
2597 Editor::get_state ()
2599 XMLNode* node = new XMLNode (X_("Editor"));
2603 id().print (buf, sizeof (buf));
2604 node->add_property ("id", buf);
2606 node->add_child_nocopy (Tabbable::get_state());
2608 snprintf(buf,sizeof(buf), "%f", edit_pane.get_divider ());
2609 node->add_property("edit-horizontal-pane-pos", string(buf));
2610 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2611 snprintf(buf,sizeof(buf), "%f", editor_summary_pane.get_divider());
2612 node->add_property("edit-vertical-pane-pos", string(buf));
2614 maybe_add_mixer_strip_width (*node);
2616 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2618 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2619 node->add_property ("zoom", buf);
2620 node->add_property ("snap-to", enum_2_string (_snap_type));
2621 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2622 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2623 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2624 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2625 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2626 node->add_property ("edit-point", enum_2_string (_edit_point));
2627 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2628 node->add_property ("visible-track-count", buf);
2630 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2631 node->add_property ("playhead", buf);
2632 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2633 node->add_property ("left-frame", buf);
2634 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2635 node->add_property ("y-origin", buf);
2637 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2638 node->add_property ("maximised", _maximised ? "yes" : "no");
2639 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2640 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2641 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2642 node->add_property ("mouse-mode", enum2str(mouse_mode));
2643 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2645 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2647 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2648 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2651 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2653 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2654 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2657 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2658 node->add_property (X_("editor-list-page"), buf);
2660 if (button_bindings) {
2661 XMLNode* bb = new XMLNode (X_("Buttons"));
2662 button_bindings->save (*bb);
2663 node->add_child_nocopy (*bb);
2666 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2668 node->add_child_nocopy (selection->get_state ());
2669 node->add_child_nocopy (_regions->get_state ());
2671 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2672 node->add_property ("nudge-clock-value", buf);
2674 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2675 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2680 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2681 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2683 * @return pair: TimeAxisView that y is over, layer index.
2685 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2686 * in stacked or expanded region display mode, otherwise 0.
2688 std::pair<TimeAxisView *, double>
2689 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2691 if (!trackview_relative_offset) {
2692 y -= _trackview_group->canvas_origin().y;
2696 return std::make_pair ( (TimeAxisView *) 0, 0);
2699 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2701 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2708 return std::make_pair ( (TimeAxisView *) 0, 0);
2711 /** Snap a position to the grid, if appropriate, taking into account current
2712 * grid settings and also the state of any snap modifier keys that may be pressed.
2713 * @param start Position to snap.
2714 * @param event Event to get current key modifier information from, or 0.
2717 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2719 if (!_session || !event) {
2723 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2724 if (_snap_mode == SnapOff) {
2725 snap_to_internal (start, direction, for_mark);
2728 if (_snap_mode != SnapOff) {
2729 snap_to_internal (start, direction, for_mark);
2730 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2731 /* SnapOff, but we pressed the snap_delta modifier */
2732 snap_to_internal (start, direction, for_mark);
2738 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2740 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2744 snap_to_internal (start, direction, for_mark, ensure_snap);
2748 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2750 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2751 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2753 switch (_snap_type) {
2754 case SnapToTimecodeFrame:
2755 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2756 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2757 /* start is already on a whole timecode frame, do nothing */
2758 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2759 start = (framepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2761 start = (framepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2765 case SnapToTimecodeSeconds:
2766 if (_session->config.get_timecode_offset_negative()) {
2767 start += _session->config.get_timecode_offset ();
2769 start -= _session->config.get_timecode_offset ();
2771 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2772 (start % one_timecode_second == 0)) {
2773 /* start is already on a whole second, do nothing */
2774 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2775 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2777 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2780 if (_session->config.get_timecode_offset_negative()) {
2781 start -= _session->config.get_timecode_offset ();
2783 start += _session->config.get_timecode_offset ();
2787 case SnapToTimecodeMinutes:
2788 if (_session->config.get_timecode_offset_negative()) {
2789 start += _session->config.get_timecode_offset ();
2791 start -= _session->config.get_timecode_offset ();
2793 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2794 (start % one_timecode_minute == 0)) {
2795 /* start is already on a whole minute, do nothing */
2796 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2797 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2799 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2801 if (_session->config.get_timecode_offset_negative()) {
2802 start -= _session->config.get_timecode_offset ();
2804 start += _session->config.get_timecode_offset ();
2808 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2809 abort(); /*NOTREACHED*/
2814 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2816 const framepos_t one_second = _session->frame_rate();
2817 const framepos_t one_minute = _session->frame_rate() * 60;
2818 framepos_t presnap = start;
2822 switch (_snap_type) {
2823 case SnapToTimecodeFrame:
2824 case SnapToTimecodeSeconds:
2825 case SnapToTimecodeMinutes:
2826 return timecode_snap_to_internal (start, direction, for_mark);
2829 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2830 start % (one_second/75) == 0) {
2831 /* start is already on a whole CD frame, do nothing */
2832 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2833 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2835 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2840 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2841 start % one_second == 0) {
2842 /* start is already on a whole second, do nothing */
2843 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2844 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2846 start = (framepos_t) floor ((double) start / one_second) * one_second;
2851 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2852 start % one_minute == 0) {
2853 /* start is already on a whole minute, do nothing */
2854 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2855 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2857 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2862 start = _session->tempo_map().round_to_bar (start, direction);
2866 start = _session->tempo_map().round_to_beat (start, direction);
2869 case SnapToBeatDiv128:
2870 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 128, direction);
2872 case SnapToBeatDiv64:
2873 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 64, direction);
2875 case SnapToBeatDiv32:
2876 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 32, direction);
2878 case SnapToBeatDiv28:
2879 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 28, direction);
2881 case SnapToBeatDiv24:
2882 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 24, direction);
2884 case SnapToBeatDiv20:
2885 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 20, direction);
2887 case SnapToBeatDiv16:
2888 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 16, direction);
2890 case SnapToBeatDiv14:
2891 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 14, direction);
2893 case SnapToBeatDiv12:
2894 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 12, direction);
2896 case SnapToBeatDiv10:
2897 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 10, direction);
2899 case SnapToBeatDiv8:
2900 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 8, direction);
2902 case SnapToBeatDiv7:
2903 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 7, direction);
2905 case SnapToBeatDiv6:
2906 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 6, direction);
2908 case SnapToBeatDiv5:
2909 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 5, direction);
2911 case SnapToBeatDiv4:
2912 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 4, direction);
2914 case SnapToBeatDiv3:
2915 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 3, direction);
2917 case SnapToBeatDiv2:
2918 start = _session->tempo_map().round_to_quarter_note_subdivision (start, 2, direction);
2926 _session->locations()->marks_either_side (start, before, after);
2928 if (before == max_framepos && after == max_framepos) {
2929 /* No marks to snap to, so just don't snap */
2931 } else if (before == max_framepos) {
2933 } else if (after == max_framepos) {
2935 } else if (before != max_framepos && after != max_framepos) {
2936 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2938 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2940 else if (direction == 0 ) {
2941 if ((start - before) < (after - start)) {
2951 case SnapToRegionStart:
2952 case SnapToRegionEnd:
2953 case SnapToRegionSync:
2954 case SnapToRegionBoundary:
2955 if (!region_boundary_cache.empty()) {
2957 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2958 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2960 if (direction > 0) {
2961 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2963 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2966 if (next != region_boundary_cache.begin ()) {
2971 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2972 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2974 if (start > (p + n) / 2) {
2983 switch (_snap_mode) {
2993 if (presnap > start) {
2994 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2998 } else if (presnap < start) {
2999 if (presnap < (start - pixel_to_sample(snap_threshold))) {
3005 /* handled at entry */
3013 Editor::setup_toolbar ()
3015 HBox* mode_box = manage(new HBox);
3016 mode_box->set_border_width (2);
3017 mode_box->set_spacing(2);
3019 HBox* mouse_mode_box = manage (new HBox);
3020 HBox* mouse_mode_hbox = manage (new HBox);
3021 VBox* mouse_mode_vbox = manage (new VBox);
3022 Alignment* mouse_mode_align = manage (new Alignment);
3024 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3025 mouse_mode_size_group->add_widget (smart_mode_button);
3026 mouse_mode_size_group->add_widget (mouse_move_button);
3027 mouse_mode_size_group->add_widget (mouse_cut_button);
3028 mouse_mode_size_group->add_widget (mouse_select_button);
3029 mouse_mode_size_group->add_widget (mouse_timefx_button);
3030 mouse_mode_size_group->add_widget (mouse_audition_button);
3031 mouse_mode_size_group->add_widget (mouse_draw_button);
3032 mouse_mode_size_group->add_widget (mouse_content_button);
3034 if (!Profile->get_mixbus()) {
3035 mouse_mode_size_group->add_widget (zoom_in_button);
3036 mouse_mode_size_group->add_widget (zoom_out_button);
3037 mouse_mode_size_group->add_widget (zoom_out_full_button);
3038 mouse_mode_size_group->add_widget (zoom_focus_selector);
3039 mouse_mode_size_group->add_widget (tav_shrink_button);
3040 mouse_mode_size_group->add_widget (tav_expand_button);
3042 mouse_mode_size_group->add_widget (zoom_preset_selector);
3043 mouse_mode_size_group->add_widget (visible_tracks_selector);
3046 mouse_mode_size_group->add_widget (snap_type_selector);
3047 mouse_mode_size_group->add_widget (snap_mode_selector);
3049 mouse_mode_size_group->add_widget (edit_point_selector);
3050 mouse_mode_size_group->add_widget (edit_mode_selector);
3052 mouse_mode_size_group->add_widget (*nudge_clock);
3053 mouse_mode_size_group->add_widget (nudge_forward_button);
3054 mouse_mode_size_group->add_widget (nudge_backward_button);
3056 mouse_mode_hbox->set_spacing (2);
3058 if (!ARDOUR::Profile->get_trx()) {
3059 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3062 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3063 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3065 if (!ARDOUR::Profile->get_mixbus()) {
3066 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3069 if (!ARDOUR::Profile->get_trx()) {
3070 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3071 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3072 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3073 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3076 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3078 mouse_mode_align->add (*mouse_mode_vbox);
3079 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3081 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3083 edit_mode_selector.set_name ("mouse mode button");
3085 if (!ARDOUR::Profile->get_trx()) {
3086 mode_box->pack_start (edit_mode_selector, false, false);
3089 mode_box->pack_start (*mouse_mode_box, false, false);
3093 _zoom_box.set_spacing (2);
3094 _zoom_box.set_border_width (2);
3098 zoom_preset_selector.set_name ("zoom button");
3099 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
3101 zoom_in_button.set_name ("zoom button");
3102 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3103 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3104 zoom_in_button.set_related_action (act);
3106 zoom_out_button.set_name ("zoom button");
3107 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3108 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3109 zoom_out_button.set_related_action (act);
3111 zoom_out_full_button.set_name ("zoom button");
3112 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3113 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3114 zoom_out_full_button.set_related_action (act);
3116 zoom_focus_selector.set_name ("zoom button");
3118 if (ARDOUR::Profile->get_mixbus()) {
3119 _zoom_box.pack_start (zoom_preset_selector, false, false);
3120 } else if (ARDOUR::Profile->get_trx()) {
3121 mode_box->pack_start (zoom_out_button, false, false);
3122 mode_box->pack_start (zoom_in_button, false, false);
3124 _zoom_box.pack_start (zoom_out_button, false, false);
3125 _zoom_box.pack_start (zoom_in_button, false, false);
3126 _zoom_box.pack_start (zoom_out_full_button, false, false);
3127 _zoom_box.pack_start (zoom_focus_selector, false, false);
3130 /* Track zoom buttons */
3131 _track_box.set_spacing (2);
3132 _track_box.set_border_width (2);
3134 visible_tracks_selector.set_name ("zoom button");
3135 if (Profile->get_mixbus()) {
3136 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3138 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3141 tav_expand_button.set_name ("zoom button");
3142 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3143 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3144 tav_expand_button.set_related_action (act);
3146 tav_shrink_button.set_name ("zoom button");
3147 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3148 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3149 tav_shrink_button.set_related_action (act);
3151 if (ARDOUR::Profile->get_mixbus()) {
3152 _track_box.pack_start (visible_tracks_selector);
3153 } else if (ARDOUR::Profile->get_trx()) {
3154 _track_box.pack_start (tav_shrink_button);
3155 _track_box.pack_start (tav_expand_button);
3157 _track_box.pack_start (visible_tracks_selector);
3158 _track_box.pack_start (tav_shrink_button);
3159 _track_box.pack_start (tav_expand_button);
3162 snap_box.set_spacing (2);
3163 snap_box.set_border_width (2);
3165 snap_type_selector.set_name ("mouse mode button");
3167 snap_mode_selector.set_name ("mouse mode button");
3169 edit_point_selector.set_name ("mouse mode button");
3171 snap_box.pack_start (snap_mode_selector, false, false);
3172 snap_box.pack_start (snap_type_selector, false, false);
3175 HBox *ep_box = manage (new HBox);
3176 ep_box->set_spacing (2);
3177 ep_box->set_border_width (2);
3179 ep_box->pack_start (edit_point_selector, false, false);
3183 HBox *nudge_box = manage (new HBox);
3184 nudge_box->set_spacing (2);
3185 nudge_box->set_border_width (2);
3187 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3188 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3190 nudge_box->pack_start (nudge_backward_button, false, false);
3191 nudge_box->pack_start (nudge_forward_button, false, false);
3192 nudge_box->pack_start (*nudge_clock, false, false);
3195 /* Pack everything in... */
3197 toolbar_hbox.set_spacing (2);
3198 toolbar_hbox.set_border_width (2);
3200 toolbar_hbox.pack_start (*mode_box, false, false);
3202 if (!ARDOUR::Profile->get_trx()) {
3204 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3206 toolbar_hbox.pack_start (_zoom_box, false, false);
3208 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3210 toolbar_hbox.pack_start (_track_box, false, false);
3212 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3214 toolbar_hbox.pack_start (snap_box, false, false);
3216 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3218 toolbar_hbox.pack_start (*ep_box, false, false);
3220 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3222 toolbar_hbox.pack_start (*nudge_box, false, false);
3225 toolbar_hbox.show_all ();
3229 Editor::build_edit_point_menu ()
3231 using namespace Menu_Helpers;
3233 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3234 if(!Profile->get_mixbus())
3235 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3236 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3238 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3242 Editor::build_edit_mode_menu ()
3244 using namespace Menu_Helpers;
3246 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3247 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3248 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3249 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3251 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3255 Editor::build_snap_mode_menu ()
3257 using namespace Menu_Helpers;
3259 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3260 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3261 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3263 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3267 Editor::build_snap_type_menu ()
3269 using namespace Menu_Helpers;
3271 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3272 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3273 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3274 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3275 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3276 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3277 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3278 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3279 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3280 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3281 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3282 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3283 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3284 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3285 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3286 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3287 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3288 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3289 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3290 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3291 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3292 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3293 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3294 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3295 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3296 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3297 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3298 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3299 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3300 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3302 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3307 Editor::setup_tooltips ()
3309 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3310 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3311 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3312 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3313 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3314 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3315 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3316 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3317 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3318 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3319 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3320 set_tooltip (zoom_in_button, _("Zoom In"));
3321 set_tooltip (zoom_out_button, _("Zoom Out"));
3322 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3323 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3324 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3325 set_tooltip (tav_expand_button, _("Expand Tracks"));
3326 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3327 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3328 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3329 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3330 set_tooltip (edit_point_selector, _("Edit Point"));
3331 set_tooltip (edit_mode_selector, _("Edit Mode"));
3332 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3336 Editor::convert_drop_to_paths (
3337 vector<string>& paths,
3338 const RefPtr<Gdk::DragContext>& /*context*/,
3341 const SelectionData& data,
3345 if (_session == 0) {
3349 vector<string> uris = data.get_uris();
3353 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3354 are actually URI lists. So do it by hand.
3357 if (data.get_target() != "text/plain") {
3361 /* Parse the "uri-list" format that Nautilus provides,
3362 where each pathname is delimited by \r\n.
3364 THERE MAY BE NO NULL TERMINATING CHAR!!!
3367 string txt = data.get_text();
3371 p = (char *) malloc (txt.length() + 1);
3372 txt.copy (p, txt.length(), 0);
3373 p[txt.length()] = '\0';
3379 while (g_ascii_isspace (*p))
3383 while (*q && (*q != '\n') && (*q != '\r')) {
3390 while (q > p && g_ascii_isspace (*q))
3395 uris.push_back (string (p, q - p + 1));
3399 p = strchr (p, '\n');
3411 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3412 if ((*i).substr (0,7) == "file://") {
3413 paths.push_back (Glib::filename_from_uri (*i));
3421 Editor::new_tempo_section ()
3426 Editor::map_transport_state ()
3428 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3430 if (_session && _session->transport_stopped()) {
3431 have_pending_keyboard_selection = false;
3434 update_loop_range_view ();
3440 Editor::begin_selection_op_history ()
3442 selection_op_cmd_depth = 0;
3443 selection_op_history_it = 0;
3445 while(!selection_op_history.empty()) {
3446 delete selection_op_history.front();
3447 selection_op_history.pop_front();
3450 selection_undo_action->set_sensitive (false);
3451 selection_redo_action->set_sensitive (false);
3452 selection_op_history.push_front (&_selection_memento->get_state ());
3456 Editor::begin_reversible_selection_op (string name)
3459 //cerr << name << endl;
3460 /* begin/commit pairs can be nested */
3461 selection_op_cmd_depth++;
3466 Editor::commit_reversible_selection_op ()
3469 if (selection_op_cmd_depth == 1) {
3471 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3473 The user has undone some selection ops and then made a new one,
3474 making anything earlier in the list invalid.
3477 list<XMLNode *>::iterator it = selection_op_history.begin();
3478 list<XMLNode *>::iterator e_it = it;
3479 advance (e_it, selection_op_history_it);
3481 for ( ; it != e_it; ++it) {
3484 selection_op_history.erase (selection_op_history.begin(), e_it);
3487 selection_op_history.push_front (&_selection_memento->get_state ());
3488 selection_op_history_it = 0;
3490 selection_undo_action->set_sensitive (true);
3491 selection_redo_action->set_sensitive (false);
3494 if (selection_op_cmd_depth > 0) {
3495 selection_op_cmd_depth--;
3501 Editor::undo_selection_op ()
3504 selection_op_history_it++;
3506 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3507 if (n == selection_op_history_it) {
3508 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3509 selection_redo_action->set_sensitive (true);
3513 /* is there an earlier entry? */
3514 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3515 selection_undo_action->set_sensitive (false);
3521 Editor::redo_selection_op ()
3524 if (selection_op_history_it > 0) {
3525 selection_op_history_it--;
3528 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3529 if (n == selection_op_history_it) {
3530 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3531 selection_undo_action->set_sensitive (true);
3536 if (selection_op_history_it == 0) {
3537 selection_redo_action->set_sensitive (false);
3543 Editor::begin_reversible_command (string name)
3546 before.push_back (&_selection_memento->get_state ());
3547 _session->begin_reversible_command (name);
3552 Editor::begin_reversible_command (GQuark q)
3555 before.push_back (&_selection_memento->get_state ());
3556 _session->begin_reversible_command (q);
3561 Editor::abort_reversible_command ()
3564 while(!before.empty()) {
3565 delete before.front();
3568 _session->abort_reversible_command ();
3573 Editor::commit_reversible_command ()
3576 if (before.size() == 1) {
3577 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3578 redo_action->set_sensitive(false);
3579 undo_action->set_sensitive(true);
3580 begin_selection_op_history ();
3583 if (before.empty()) {
3584 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3589 _session->commit_reversible_command ();
3594 Editor::history_changed ()
3598 if (undo_action && _session) {
3599 if (_session->undo_depth() == 0) {
3600 label = S_("Command|Undo");
3602 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3604 undo_action->property_label() = label;
3607 if (redo_action && _session) {
3608 if (_session->redo_depth() == 0) {
3610 redo_action->set_sensitive (false);
3612 label = string_compose(_("Redo (%1)"), _session->next_redo());
3613 redo_action->set_sensitive (true);
3615 redo_action->property_label() = label;
3620 Editor::duplicate_range (bool with_dialog)
3624 RegionSelection rs = get_regions_from_selection_and_entered ();
3626 if ( selection->time.length() == 0 && rs.empty()) {
3632 ArdourDialog win (_("Duplicate"));
3633 Label label (_("Number of duplications:"));
3634 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3635 SpinButton spinner (adjustment, 0.0, 1);
3638 win.get_vbox()->set_spacing (12);
3639 win.get_vbox()->pack_start (hbox);
3640 hbox.set_border_width (6);
3641 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3643 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3644 place, visually. so do this by hand.
3647 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3648 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3649 spinner.grab_focus();
3655 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3656 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3657 win.set_default_response (RESPONSE_ACCEPT);
3659 spinner.grab_focus ();
3661 switch (win.run ()) {
3662 case RESPONSE_ACCEPT:
3668 times = adjustment.get_value();
3671 if ((current_mouse_mode() == Editing::MouseRange)) {
3672 if (selection->time.length()) {
3673 duplicate_selection (times);
3675 } else if (get_smart_mode()) {
3676 if (selection->time.length()) {
3677 duplicate_selection (times);
3679 duplicate_some_regions (rs, times);
3681 duplicate_some_regions (rs, times);
3686 Editor::set_edit_mode (EditMode m)
3688 Config->set_edit_mode (m);
3692 Editor::cycle_edit_mode ()
3694 switch (Config->get_edit_mode()) {
3696 Config->set_edit_mode (Ripple);
3700 Config->set_edit_mode (Lock);
3703 Config->set_edit_mode (Slide);
3709 Editor::edit_mode_selection_done ( EditMode m )
3711 Config->set_edit_mode ( m );
3715 Editor::snap_type_selection_done (SnapType snaptype)
3717 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3719 ract->set_active ();
3724 Editor::snap_mode_selection_done (SnapMode mode)
3726 RefPtr<RadioAction> ract = snap_mode_action (mode);
3729 ract->set_active (true);
3734 Editor::cycle_edit_point (bool with_marker)
3736 if(Profile->get_mixbus())
3737 with_marker = false;
3739 switch (_edit_point) {
3741 set_edit_point_preference (EditAtPlayhead);
3743 case EditAtPlayhead:
3745 set_edit_point_preference (EditAtSelectedMarker);
3747 set_edit_point_preference (EditAtMouse);
3750 case EditAtSelectedMarker:
3751 set_edit_point_preference (EditAtMouse);
3757 Editor::edit_point_selection_done (EditPoint ep)
3759 set_edit_point_preference ( ep );
3763 Editor::build_zoom_focus_menu ()
3765 using namespace Menu_Helpers;
3767 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3768 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3769 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3770 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3771 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3772 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3774 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3778 Editor::zoom_focus_selection_done ( ZoomFocus f )
3780 RefPtr<RadioAction> ract = zoom_focus_action (f);
3782 ract->set_active ();
3787 Editor::build_track_count_menu ()
3789 using namespace Menu_Helpers;
3791 if (!Profile->get_mixbus()) {
3792 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3793 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3794 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3795 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3796 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3797 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3798 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3799 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3800 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3801 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3802 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3803 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3804 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3806 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3807 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3808 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3809 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3810 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3811 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3812 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3813 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3814 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3815 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3817 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3818 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3819 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3820 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3821 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3822 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3823 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3824 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3825 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3826 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3827 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3832 Editor::set_zoom_preset (int64_t ms)
3835 temporal_zoom_session();
3839 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3840 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3844 Editor::set_visible_track_count (int32_t n)
3846 _visible_track_count = n;
3848 /* if the canvas hasn't really been allocated any size yet, just
3849 record the desired number of visible tracks and return. when canvas
3850 allocation happens, we will get called again and then we can do the
3854 if (_visible_canvas_height <= 1) {
3860 DisplaySuspender ds;
3862 if (_visible_track_count > 0) {
3863 h = trackviews_height() / _visible_track_count;
3864 std::ostringstream s;
3865 s << _visible_track_count;
3867 } else if (_visible_track_count == 0) {
3869 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3870 if ((*i)->marked_for_display()) {
3874 h = trackviews_height() / n;
3877 /* negative value means that the visible track count has
3878 been overridden by explicit track height changes.
3880 visible_tracks_selector.set_text (X_("*"));
3884 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3885 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3888 if (str != visible_tracks_selector.get_text()) {
3889 visible_tracks_selector.set_text (str);
3894 Editor::override_visible_track_count ()
3896 _visible_track_count = -1;
3897 visible_tracks_selector.set_text ( _("*") );
3901 Editor::edit_controls_button_release (GdkEventButton* ev)
3903 if (Keyboard::is_context_menu_event (ev)) {
3904 ARDOUR_UI::instance()->add_route ();
3905 } else if (ev->button == 1) {
3906 selection->clear_tracks ();
3913 Editor::mouse_select_button_release (GdkEventButton* ev)
3915 /* this handles just right-clicks */
3917 if (ev->button != 3) {
3925 Editor::set_zoom_focus (ZoomFocus f)
3927 string str = zoom_focus_strings[(int)f];
3929 if (str != zoom_focus_selector.get_text()) {
3930 zoom_focus_selector.set_text (str);
3933 if (zoom_focus != f) {
3940 Editor::cycle_zoom_focus ()
3942 switch (zoom_focus) {
3944 set_zoom_focus (ZoomFocusRight);
3946 case ZoomFocusRight:
3947 set_zoom_focus (ZoomFocusCenter);
3949 case ZoomFocusCenter:
3950 set_zoom_focus (ZoomFocusPlayhead);
3952 case ZoomFocusPlayhead:
3953 set_zoom_focus (ZoomFocusMouse);
3955 case ZoomFocusMouse:
3956 set_zoom_focus (ZoomFocusEdit);
3959 set_zoom_focus (ZoomFocusLeft);
3965 Editor::set_show_measures (bool yn)
3967 if (_show_measures != yn) {
3970 if ((_show_measures = yn) == true) {
3972 tempo_lines->show();
3975 std::vector<TempoMap::BBTPoint> grid;
3976 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3977 draw_measures (grid);
3985 Editor::toggle_follow_playhead ()
3987 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3989 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3990 set_follow_playhead (tact->get_active());
3994 /** @param yn true to follow playhead, otherwise false.
3995 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3998 Editor::set_follow_playhead (bool yn, bool catch_up)
4000 if (_follow_playhead != yn) {
4001 if ((_follow_playhead = yn) == true && catch_up) {
4003 reset_x_origin_to_follow_playhead ();
4010 Editor::toggle_stationary_playhead ()
4012 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4014 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4015 set_stationary_playhead (tact->get_active());
4020 Editor::set_stationary_playhead (bool yn)
4022 if (_stationary_playhead != yn) {
4023 if ((_stationary_playhead = yn) == true) {
4025 // FIXME need a 3.0 equivalent of this 2.X call
4026 // update_current_screen ();
4033 Editor::playlist_selector () const
4035 return *_playlist_selector;
4039 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4041 if (paste_count == 0) {
4042 /* don't bother calculating an offset that will be zero anyway */
4046 /* calculate basic unsnapped multi-paste offset */
4047 framecnt_t offset = paste_count * duration;
4049 /* snap offset so pos + offset is aligned to the grid */
4050 framepos_t offset_pos = pos + offset;
4051 snap_to(offset_pos, RoundUpMaybe);
4052 offset = offset_pos - pos;
4058 Editor::get_grid_beat_divisions(framepos_t position)
4060 switch (_snap_type) {
4061 case SnapToBeatDiv128: return 128;
4062 case SnapToBeatDiv64: return 64;
4063 case SnapToBeatDiv32: return 32;
4064 case SnapToBeatDiv28: return 28;
4065 case SnapToBeatDiv24: return 24;
4066 case SnapToBeatDiv20: return 20;
4067 case SnapToBeatDiv16: return 16;
4068 case SnapToBeatDiv14: return 14;
4069 case SnapToBeatDiv12: return 12;
4070 case SnapToBeatDiv10: return 10;
4071 case SnapToBeatDiv8: return 8;
4072 case SnapToBeatDiv7: return 7;
4073 case SnapToBeatDiv6: return 6;
4074 case SnapToBeatDiv5: return 5;
4075 case SnapToBeatDiv4: return 4;
4076 case SnapToBeatDiv3: return 3;
4077 case SnapToBeatDiv2: return 2;
4083 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4084 if the grid is non-musical, returns 0.
4085 if the grid is snapped to bars, returns -1.
4086 @param event_state the current keyboard modifier mask.
4089 Editor::get_grid_music_divisions (uint32_t event_state)
4091 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4095 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4099 switch (_snap_type) {
4100 case SnapToBeatDiv128: return 128;
4101 case SnapToBeatDiv64: return 64;
4102 case SnapToBeatDiv32: return 32;
4103 case SnapToBeatDiv28: return 28;
4104 case SnapToBeatDiv24: return 24;
4105 case SnapToBeatDiv20: return 20;
4106 case SnapToBeatDiv16: return 16;
4107 case SnapToBeatDiv14: return 14;
4108 case SnapToBeatDiv12: return 12;
4109 case SnapToBeatDiv10: return 10;
4110 case SnapToBeatDiv8: return 8;
4111 case SnapToBeatDiv7: return 7;
4112 case SnapToBeatDiv6: return 6;
4113 case SnapToBeatDiv5: return 5;
4114 case SnapToBeatDiv4: return 4;
4115 case SnapToBeatDiv3: return 3;
4116 case SnapToBeatDiv2: return 2;
4117 case SnapToBeat: return 1;
4118 case SnapToBar : return -1;
4125 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4129 const unsigned divisions = get_grid_beat_divisions(position);
4131 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4134 switch (_snap_type) {
4136 return Evoral::Beats(4.0 / _session->tempo_map().meter_at_frame (position).note_divisor());
4139 const Meter& m = _session->tempo_map().meter_at_frame (position);
4140 return Evoral::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4148 return Evoral::Beats();
4152 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4156 ret = nudge_clock->current_duration (pos);
4157 next = ret + 1; /* XXXX fix me */
4163 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4165 ArdourDialog dialog (_("Playlist Deletion"));
4166 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4167 "If it is kept, its audio files will not be cleaned.\n"
4168 "If it is deleted, audio files used by it alone will be cleaned."),
4171 dialog.set_position (WIN_POS_CENTER);
4172 dialog.get_vbox()->pack_start (label);
4176 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4177 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4178 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4179 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4180 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4182 // by default gtk uses the left most button
4183 keep->grab_focus ();
4185 switch (dialog.run ()) {
4187 /* keep this and all remaining ones */
4192 /* delete this and all others */
4196 case RESPONSE_ACCEPT:
4197 /* delete the playlist */
4201 case RESPONSE_REJECT:
4202 /* keep the playlist */
4214 Editor::audio_region_selection_covers (framepos_t where)
4216 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4217 if ((*a)->region()->covers (where)) {
4226 Editor::prepare_for_cleanup ()
4228 cut_buffer->clear_regions ();
4229 cut_buffer->clear_playlists ();
4231 selection->clear_regions ();
4232 selection->clear_playlists ();
4234 _regions->suspend_redisplay ();
4238 Editor::finish_cleanup ()
4240 _regions->resume_redisplay ();
4244 Editor::transport_loop_location()
4247 return _session->locations()->auto_loop_location();
4254 Editor::transport_punch_location()
4257 return _session->locations()->auto_punch_location();
4264 Editor::control_layout_scroll (GdkEventScroll* ev)
4266 /* Just forward to the normal canvas scroll method. The coordinate
4267 systems are different but since the canvas is always larger than the
4268 track headers, and aligned with the trackview area, this will work.
4270 In the not too distant future this layout is going away anyway and
4271 headers will be on the canvas.
4273 return canvas_scroll_event (ev, false);
4277 Editor::session_state_saved (string)
4280 _snapshots->redisplay ();
4284 Editor::maximise_editing_space ()
4290 Gtk::Window* toplevel = current_toplevel();
4293 toplevel->fullscreen ();
4299 Editor::restore_editing_space ()
4305 Gtk::Window* toplevel = current_toplevel();
4308 toplevel->unfullscreen();
4314 * Make new playlists for a given track and also any others that belong
4315 * to the same active route group with the `select' property.
4320 Editor::new_playlists (TimeAxisView* v)
4322 begin_reversible_command (_("new playlists"));
4323 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4324 _session->playlists->get (playlists);
4325 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4326 commit_reversible_command ();
4330 * Use a copy of the current playlist for a given track and also any others that belong
4331 * to the same active route group with the `select' property.
4336 Editor::copy_playlists (TimeAxisView* v)
4338 begin_reversible_command (_("copy playlists"));
4339 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4340 _session->playlists->get (playlists);
4341 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4342 commit_reversible_command ();
4345 /** Clear the current playlist for a given track and also any others that belong
4346 * to the same active route group with the `select' property.
4351 Editor::clear_playlists (TimeAxisView* v)
4353 begin_reversible_command (_("clear playlists"));
4354 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4355 _session->playlists->get (playlists);
4356 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4357 commit_reversible_command ();
4361 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4363 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4367 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4369 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4373 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4375 atv.clear_playlist ();
4379 Editor::get_y_origin () const
4381 return vertical_adjustment.get_value ();
4384 /** Queue up a change to the viewport x origin.
4385 * @param frame New x origin.
4388 Editor::reset_x_origin (framepos_t frame)
4390 pending_visual_change.add (VisualChange::TimeOrigin);
4391 pending_visual_change.time_origin = frame;
4392 ensure_visual_change_idle_handler ();
4396 Editor::reset_y_origin (double y)
4398 pending_visual_change.add (VisualChange::YOrigin);
4399 pending_visual_change.y_origin = y;
4400 ensure_visual_change_idle_handler ();
4404 Editor::reset_zoom (framecnt_t spp)
4406 if (spp == samples_per_pixel) {
4410 pending_visual_change.add (VisualChange::ZoomLevel);
4411 pending_visual_change.samples_per_pixel = spp;
4412 ensure_visual_change_idle_handler ();
4416 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4418 reset_x_origin (frame);
4421 if (!no_save_visual) {
4422 undo_visual_stack.push_back (current_visual_state(false));
4426 Editor::VisualState::VisualState (bool with_tracks)
4427 : gui_state (with_tracks ? new GUIObjectState : 0)
4431 Editor::VisualState::~VisualState ()
4436 Editor::VisualState*
4437 Editor::current_visual_state (bool with_tracks)
4439 VisualState* vs = new VisualState (with_tracks);
4440 vs->y_position = vertical_adjustment.get_value();
4441 vs->samples_per_pixel = samples_per_pixel;
4442 vs->leftmost_frame = leftmost_frame;
4443 vs->zoom_focus = zoom_focus;
4446 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4453 Editor::undo_visual_state ()
4455 if (undo_visual_stack.empty()) {
4459 VisualState* vs = undo_visual_stack.back();
4460 undo_visual_stack.pop_back();
4463 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4466 use_visual_state (*vs);
4471 Editor::redo_visual_state ()
4473 if (redo_visual_stack.empty()) {
4477 VisualState* vs = redo_visual_stack.back();
4478 redo_visual_stack.pop_back();
4480 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4481 // why do we check here?
4482 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4485 use_visual_state (*vs);
4490 Editor::swap_visual_state ()
4492 if (undo_visual_stack.empty()) {
4493 redo_visual_state ();
4495 undo_visual_state ();
4500 Editor::use_visual_state (VisualState& vs)
4502 PBD::Unwinder<bool> nsv (no_save_visual, true);
4503 DisplaySuspender ds;
4505 vertical_adjustment.set_value (vs.y_position);
4507 set_zoom_focus (vs.zoom_focus);
4508 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4511 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4513 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4514 (*i)->clear_property_cache();
4515 (*i)->reset_visual_state ();
4519 _routes->update_visibility ();
4522 /** This is the core function that controls the zoom level of the canvas. It is called
4523 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4524 * @param spp new number of samples per pixel
4527 Editor::set_samples_per_pixel (framecnt_t spp)
4533 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4534 const framecnt_t lots_of_pixels = 4000;
4536 /* if the zoom level is greater than what you'd get trying to display 3
4537 * days of audio on a really big screen, then it's too big.
4540 if (spp * lots_of_pixels > three_days) {
4544 samples_per_pixel = spp;
4547 tempo_lines->tempo_map_changed();
4550 bool const showing_time_selection = selection->time.length() > 0;
4552 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4553 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4554 (*i)->reshow_selection (selection->time);
4558 ZoomChanged (); /* EMIT_SIGNAL */
4560 ArdourCanvas::GtkCanvasViewport* c;
4562 c = get_track_canvas();
4564 c->canvas()->zoomed ();
4567 if (playhead_cursor) {
4568 playhead_cursor->set_position (playhead_cursor->current_frame ());
4571 refresh_location_display();
4572 _summary->set_overlays_dirty ();
4574 update_marker_labels ();
4580 Editor::playhead_cursor_sample () const
4582 return playhead_cursor->current_frame();
4586 Editor::queue_visual_videotimeline_update ()
4589 * pending_visual_change.add (VisualChange::VideoTimeline);
4590 * or maybe even more specific: which videotimeline-image
4591 * currently it calls update_video_timeline() to update
4592 * _all outdated_ images on the video-timeline.
4593 * see 'exposeimg()' in video_image_frame.cc
4595 ensure_visual_change_idle_handler ();
4599 Editor::ensure_visual_change_idle_handler ()
4601 if (pending_visual_change.idle_handler_id < 0) {
4602 // see comment in add_to_idle_resize above.
4603 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4604 pending_visual_change.being_handled = false;
4609 Editor::_idle_visual_changer (void* arg)
4611 return static_cast<Editor*>(arg)->idle_visual_changer ();
4615 Editor::idle_visual_changer ()
4617 /* set_horizontal_position() below (and maybe other calls) call
4618 gtk_main_iteration(), so it's possible that a signal will be handled
4619 half-way through this method. If this signal wants an
4620 idle_visual_changer we must schedule another one after this one, so
4621 mark the idle_handler_id as -1 here to allow that. Also make a note
4622 that we are doing the visual change, so that changes in response to
4623 super-rapid-screen-update can be dropped if we are still processing
4627 pending_visual_change.idle_handler_id = -1;
4628 pending_visual_change.being_handled = true;
4630 VisualChange vc = pending_visual_change;
4632 pending_visual_change.pending = (VisualChange::Type) 0;
4634 visual_changer (vc);
4636 pending_visual_change.being_handled = false;
4638 return 0; /* this is always a one-shot call */
4642 Editor::visual_changer (const VisualChange& vc)
4644 double const last_time_origin = horizontal_position ();
4646 if (vc.pending & VisualChange::ZoomLevel) {
4647 set_samples_per_pixel (vc.samples_per_pixel);
4649 compute_fixed_ruler_scale ();
4651 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4652 update_tempo_based_rulers ();
4654 update_video_timeline();
4657 if (vc.pending & VisualChange::TimeOrigin) {
4658 set_horizontal_position (vc.time_origin / samples_per_pixel);
4661 if (vc.pending & VisualChange::YOrigin) {
4662 vertical_adjustment.set_value (vc.y_origin);
4665 if (last_time_origin == horizontal_position ()) {
4666 /* changed signal not emitted */
4667 update_fixed_rulers ();
4668 redisplay_tempo (true);
4671 if (!(vc.pending & VisualChange::ZoomLevel)) {
4672 update_video_timeline();
4675 _summary->set_overlays_dirty ();
4678 struct EditorOrderTimeAxisSorter {
4679 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4680 return a->order () < b->order ();
4685 Editor::sort_track_selection (TrackViewList& sel)
4687 EditorOrderTimeAxisSorter cmp;
4692 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4695 framepos_t where = 0;
4696 EditPoint ep = _edit_point;
4698 if (Profile->get_mixbus()) {
4699 if (ep == EditAtSelectedMarker) {
4700 ep = EditAtPlayhead;
4704 if (from_outside_canvas && (ep == EditAtMouse)) {
4705 ep = EditAtPlayhead;
4706 } else if (from_context_menu && (ep == EditAtMouse)) {
4707 return canvas_event_sample (&context_click_event, 0, 0);
4710 if (entered_marker) {
4711 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4712 return entered_marker->position();
4715 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4716 ep = EditAtSelectedMarker;
4719 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4720 ep = EditAtPlayhead;
4724 case EditAtPlayhead:
4725 if (_dragging_playhead) {
4726 where = *_control_scroll_target;
4728 where = _session->audible_frame();
4730 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4733 case EditAtSelectedMarker:
4734 if (!selection->markers.empty()) {
4736 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4739 where = loc->start();
4743 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4751 if (!mouse_frame (where, ignored)) {
4752 /* XXX not right but what can we do ? */
4756 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4764 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4766 if (!_session) return;
4768 begin_reversible_command (cmd);
4772 if ((tll = transport_loop_location()) == 0) {
4773 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4774 XMLNode &before = _session->locations()->get_state();
4775 _session->locations()->add (loc, true);
4776 _session->set_auto_loop_location (loc);
4777 XMLNode &after = _session->locations()->get_state();
4778 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4780 XMLNode &before = tll->get_state();
4781 tll->set_hidden (false, this);
4782 tll->set (start, end);
4783 XMLNode &after = tll->get_state();
4784 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4787 commit_reversible_command ();
4791 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4793 if (!_session) return;
4795 begin_reversible_command (cmd);
4799 if ((tpl = transport_punch_location()) == 0) {
4800 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4801 XMLNode &before = _session->locations()->get_state();
4802 _session->locations()->add (loc, true);
4803 _session->set_auto_punch_location (loc);
4804 XMLNode &after = _session->locations()->get_state();
4805 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4807 XMLNode &before = tpl->get_state();
4808 tpl->set_hidden (false, this);
4809 tpl->set (start, end);
4810 XMLNode &after = tpl->get_state();
4811 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4814 commit_reversible_command ();
4817 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4818 * @param rs List to which found regions are added.
4819 * @param where Time to look at.
4820 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4823 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4825 const TrackViewList* tracks;
4828 tracks = &track_views;
4833 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4835 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4838 boost::shared_ptr<Track> tr;
4839 boost::shared_ptr<Playlist> pl;
4841 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4843 boost::shared_ptr<RegionList> regions = pl->regions_at (
4844 (framepos_t) floor ( (double) where * tr->speed()));
4846 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4847 RegionView* rv = rtv->view()->find_view (*i);
4858 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4860 const TrackViewList* tracks;
4863 tracks = &track_views;
4868 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4869 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4871 boost::shared_ptr<Track> tr;
4872 boost::shared_ptr<Playlist> pl;
4874 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4876 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4877 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4879 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4881 RegionView* rv = rtv->view()->find_view (*i);
4892 /** Get regions using the following method:
4894 * Make a region list using:
4895 * (a) any selected regions
4896 * (b) the intersection of any selected tracks and the edit point(*)
4897 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4899 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4901 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4905 Editor::get_regions_from_selection_and_edit_point ()
4907 RegionSelection regions;
4909 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4910 regions.add (entered_regionview);
4912 regions = selection->regions;
4915 if ( regions.empty() ) {
4916 TrackViewList tracks = selection->tracks;
4918 if (!tracks.empty()) {
4919 /* no region selected or entered, but some selected tracks:
4920 * act on all regions on the selected tracks at the edit point
4922 framepos_t const where = get_preferred_edit_position ();
4923 get_regions_at(regions, where, tracks);
4930 /** Get regions using the following method:
4932 * Make a region list using:
4933 * (a) any selected regions
4934 * (b) the intersection of any selected tracks and the edit point(*)
4935 * (c) if neither exists, then whatever region is under the mouse
4937 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4939 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4942 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4944 RegionSelection regions;
4946 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4947 regions.add (entered_regionview);
4949 regions = selection->regions;
4952 if ( regions.empty() ) {
4953 TrackViewList tracks = selection->tracks;
4955 if (!tracks.empty()) {
4956 /* no region selected or entered, but some selected tracks:
4957 * act on all regions on the selected tracks at the edit point
4959 get_regions_at(regions, pos, tracks);
4966 /** Start with regions that are selected, or the entered regionview if none are selected.
4967 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4968 * of the regions that we started with.
4972 Editor::get_regions_from_selection_and_entered () const
4974 RegionSelection regions = selection->regions;
4976 if (regions.empty() && entered_regionview) {
4977 regions.add (entered_regionview);
4984 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4986 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4987 RouteTimeAxisView* rtav;
4989 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4990 boost::shared_ptr<Playlist> pl;
4991 std::vector<boost::shared_ptr<Region> > results;
4992 boost::shared_ptr<Track> tr;
4994 if ((tr = rtav->track()) == 0) {
4999 if ((pl = (tr->playlist())) != 0) {
5000 boost::shared_ptr<Region> r = pl->region_by_id (id);
5002 RegionView* rv = rtav->view()->find_view (r);
5004 regions.push_back (rv);
5013 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5016 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5017 MidiTimeAxisView* mtav;
5019 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5021 mtav->get_per_region_note_selection (selection);
5028 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5030 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5032 RouteTimeAxisView* tatv;
5034 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5036 boost::shared_ptr<Playlist> pl;
5037 vector<boost::shared_ptr<Region> > results;
5039 boost::shared_ptr<Track> tr;
5041 if ((tr = tatv->track()) == 0) {
5046 if ((pl = (tr->playlist())) != 0) {
5047 if (src_comparison) {
5048 pl->get_source_equivalent_regions (region, results);
5050 pl->get_region_list_equivalent_regions (region, results);
5054 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5055 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5056 regions.push_back (marv);
5065 Editor::show_rhythm_ferret ()
5067 if (rhythm_ferret == 0) {
5068 rhythm_ferret = new RhythmFerret(*this);
5071 rhythm_ferret->set_session (_session);
5072 rhythm_ferret->show ();
5073 rhythm_ferret->present ();
5077 Editor::first_idle ()
5079 MessageDialog* dialog = 0;
5081 if (track_views.size() > 1) {
5082 Timers::TimerSuspender t;
5083 dialog = new MessageDialog (
5084 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5088 ARDOUR_UI::instance()->flush_pending (60);
5091 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5095 // first idle adds route children (automation tracks), so we need to redisplay here
5096 _routes->redisplay ();
5100 if (_session->undo_depth() == 0) {
5101 undo_action->set_sensitive(false);
5103 redo_action->set_sensitive(false);
5104 begin_selection_op_history ();
5110 Editor::_idle_resize (gpointer arg)
5112 return ((Editor*)arg)->idle_resize ();
5116 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5118 if (resize_idle_id < 0) {
5119 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5120 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5121 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5123 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5124 _pending_resize_amount = 0;
5127 /* make a note of the smallest resulting height, so that we can clamp the
5128 lower limit at TimeAxisView::hSmall */
5130 int32_t min_resulting = INT32_MAX;
5132 _pending_resize_amount += h;
5133 _pending_resize_view = view;
5135 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5137 if (selection->tracks.contains (_pending_resize_view)) {
5138 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5139 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5143 if (min_resulting < 0) {
5148 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5149 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5153 /** Handle pending resizing of tracks */
5155 Editor::idle_resize ()
5157 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5159 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5160 selection->tracks.contains (_pending_resize_view)) {
5162 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5163 if (*i != _pending_resize_view) {
5164 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5169 _pending_resize_amount = 0;
5170 _group_tabs->set_dirty ();
5171 resize_idle_id = -1;
5179 ENSURE_GUI_THREAD (*this, &Editor::located);
5182 playhead_cursor->set_position (_session->audible_frame ());
5183 if (_follow_playhead && !_pending_initial_locate) {
5184 reset_x_origin_to_follow_playhead ();
5188 _pending_locate_request = false;
5189 _pending_initial_locate = false;
5193 Editor::region_view_added (RegionView * rv)
5195 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5196 if (rv->region ()->id () == (*pr)) {
5197 selection->add (rv);
5198 selection->regions.pending.erase (pr);
5203 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5205 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5206 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5207 if (rv->region()->id () == (*rnote).first) {
5208 mrv->select_notes ((*rnote).second);
5209 selection->pending_midi_note_selection.erase(rnote);
5215 _summary->set_background_dirty ();
5219 Editor::region_view_removed ()
5221 _summary->set_background_dirty ();
5225 Editor::axis_view_from_stripable (boost::shared_ptr<Stripable> s) const
5227 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5228 if ((*j)->stripable() == s) {
5238 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5242 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5243 TimeAxisView* tv = axis_view_from_stripable (*i);
5253 Editor::suspend_route_redisplay ()
5256 _routes->suspend_redisplay();
5261 Editor::resume_route_redisplay ()
5264 _routes->redisplay(); // queue redisplay
5265 _routes->resume_redisplay();
5270 Editor::add_vcas (VCAList& vlist)
5274 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5275 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5278 add_stripables (sl);
5282 Editor::add_routes (RouteList& rlist)
5286 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5290 add_stripables (sl);
5294 Editor::add_stripables (StripableList& sl)
5296 list<TimeAxisView*> new_views;
5297 boost::shared_ptr<VCA> v;
5298 boost::shared_ptr<Route> r;
5299 TrackViewList new_selection;
5300 bool from_scratch = (track_views.size() == 0);
5302 sl.sort (StripablePresentationInfoSorter());
5304 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5306 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5308 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5310 new_views.push_back (vtv);
5312 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5314 if (r->is_auditioner() || r->is_monitor()) {
5318 RouteTimeAxisView* rtv;
5319 DataType dt = r->input()->default_type();
5321 if (dt == ARDOUR::DataType::AUDIO) {
5322 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5324 } else if (dt == ARDOUR::DataType::MIDI) {
5325 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5328 throw unknown_type();
5331 new_views.push_back (rtv);
5332 track_views.push_back (rtv);
5333 new_selection.push_back (rtv);
5335 rtv->effective_gain_display ();
5337 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5338 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5342 if (new_views.size() > 0) {
5343 _routes->time_axis_views_added (new_views);
5344 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5347 /* note: !new_selection.empty() means that we got some routes rather
5351 if (!from_scratch && !new_selection.empty()) {
5352 selection->tracks.clear();
5353 selection->add (new_selection);
5354 begin_selection_op_history();
5357 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5358 show_editor_mixer (true);
5361 editor_list_button.set_sensitive (true);
5365 Editor::timeaxisview_deleted (TimeAxisView *tv)
5367 if (tv == entered_track) {
5371 if (_session && _session->deletion_in_progress()) {
5372 /* the situation is under control */
5376 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5378 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5380 _routes->route_removed (tv);
5382 TimeAxisView::Children c = tv->get_child_list ();
5383 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5384 if (entered_track == i->get()) {
5389 /* remove it from the list of track views */
5391 TrackViewList::iterator i;
5393 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5394 i = track_views.erase (i);
5397 /* update whatever the current mixer strip is displaying, if revelant */
5399 boost::shared_ptr<Route> route;
5402 route = rtav->route ();
5405 if (current_mixer_strip && current_mixer_strip->route() == route) {
5407 TimeAxisView* next_tv;
5409 if (track_views.empty()) {
5411 } else if (i == track_views.end()) {
5412 next_tv = track_views.front();
5417 // skip VCAs (cannot be selected, n/a in editor-mixer)
5418 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5419 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5420 next_tv = track_views.front();
5422 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5423 /* just in case: no master, only a VCA remains */
5429 set_selected_mixer_strip (*next_tv);
5431 /* make the editor mixer strip go away setting the
5432 * button to inactive (which also unticks the menu option)
5435 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5441 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5443 if (apply_to_selection) {
5444 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5446 TrackSelection::iterator j = i;
5449 hide_track_in_display (*i, false);
5454 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5456 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5457 // this will hide the mixer strip
5458 set_selected_mixer_strip (*tv);
5461 _routes->hide_track_in_display (*tv);
5466 Editor::sync_track_view_list_and_routes ()
5468 track_views = TrackViewList (_routes->views ());
5470 _summary->set_background_dirty();
5471 _group_tabs->set_dirty ();
5473 return false; // do not call again (until needed)
5477 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5479 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5484 /** Find a RouteTimeAxisView by the ID of its route */
5486 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5488 RouteTimeAxisView* v;
5490 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5491 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5492 if(v->route()->id() == id) {
5502 Editor::fit_route_group (RouteGroup *g)
5504 TrackViewList ts = axis_views_from_routes (g->route_list ());
5509 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5511 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5514 _session->cancel_audition ();
5518 if (_session->is_auditioning()) {
5519 _session->cancel_audition ();
5520 if (r == last_audition_region) {
5525 _session->audition_region (r);
5526 last_audition_region = r;
5531 Editor::hide_a_region (boost::shared_ptr<Region> r)
5533 r->set_hidden (true);
5537 Editor::show_a_region (boost::shared_ptr<Region> r)
5539 r->set_hidden (false);
5543 Editor::audition_region_from_region_list ()
5545 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5549 Editor::hide_region_from_region_list ()
5551 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5555 Editor::show_region_in_region_list ()
5557 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5561 Editor::step_edit_status_change (bool yn)
5564 start_step_editing ();
5566 stop_step_editing ();
5571 Editor::start_step_editing ()
5573 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5577 Editor::stop_step_editing ()
5579 step_edit_connection.disconnect ();
5583 Editor::check_step_edit ()
5585 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5586 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5588 mtv->check_step_edit ();
5592 return true; // do it again, till we stop
5596 Editor::scroll_press (Direction dir)
5598 ++_scroll_callbacks;
5600 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5601 /* delay the first auto-repeat */
5607 scroll_backward (1);
5615 scroll_up_one_track ();
5619 scroll_down_one_track ();
5623 /* do hacky auto-repeat */
5624 if (!_scroll_connection.connected ()) {
5626 _scroll_connection = Glib::signal_timeout().connect (
5627 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5630 _scroll_callbacks = 0;
5637 Editor::scroll_release ()
5639 _scroll_connection.disconnect ();
5642 /** Queue a change for the Editor viewport x origin to follow the playhead */
5644 Editor::reset_x_origin_to_follow_playhead ()
5646 framepos_t const frame = playhead_cursor->current_frame ();
5648 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5650 if (_session->transport_speed() < 0) {
5652 if (frame > (current_page_samples() / 2)) {
5653 center_screen (frame-(current_page_samples()/2));
5655 center_screen (current_page_samples()/2);
5662 if (frame < leftmost_frame) {
5664 if (_session->transport_rolling()) {
5665 /* rolling; end up with the playhead at the right of the page */
5666 l = frame - current_page_samples ();
5668 /* not rolling: end up with the playhead 1/4 of the way along the page */
5669 l = frame - current_page_samples() / 4;
5673 if (_session->transport_rolling()) {
5674 /* rolling: end up with the playhead on the left of the page */
5677 /* not rolling: end up with the playhead 3/4 of the way along the page */
5678 l = frame - 3 * current_page_samples() / 4;
5686 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5692 Editor::super_rapid_screen_update ()
5694 if (!_session || !_session->engine().running()) {
5698 /* METERING / MIXER STRIPS */
5700 /* update track meters, if required */
5701 if (contents().is_mapped() && meters_running) {
5702 RouteTimeAxisView* rtv;
5703 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5704 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5705 rtv->fast_update ();
5710 /* and any current mixer strip */
5711 if (current_mixer_strip) {
5712 current_mixer_strip->fast_update ();
5715 /* PLAYHEAD AND VIEWPORT */
5717 framepos_t const frame = _session->audible_frame();
5719 /* There are a few reasons why we might not update the playhead / viewport stuff:
5721 * 1. we don't update things when there's a pending locate request, otherwise
5722 * when the editor requests a locate there is a chance that this method
5723 * will move the playhead before the locate request is processed, causing
5725 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5726 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5729 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5731 last_update_frame = frame;
5733 if (!_dragging_playhead) {
5734 playhead_cursor->set_position (frame);
5737 if (!_stationary_playhead) {
5739 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5740 /* We only do this if we aren't already
5741 handling a visual change (ie if
5742 pending_visual_change.being_handled is
5743 false) so that these requests don't stack
5744 up there are too many of them to handle in
5747 reset_x_origin_to_follow_playhead ();
5752 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5753 framepos_t const frame = playhead_cursor->current_frame ();
5754 double target = ((double)frame - (double)current_page_samples()/2.0);
5755 if (target <= 0.0) {
5758 // compare to EditorCursor::set_position()
5759 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5760 double const new_pos = sample_to_pixel_unrounded (target);
5761 if (rint (new_pos) != rint (old_pos)) {
5762 reset_x_origin (pixel_to_sample (floor (new_pos)));
5773 Editor::session_going_away ()
5775 _have_idled = false;
5777 _session_connections.drop_connections ();
5779 super_rapid_screen_update_connection.disconnect ();
5781 selection->clear ();
5782 cut_buffer->clear ();
5784 clicked_regionview = 0;
5785 clicked_axisview = 0;
5786 clicked_routeview = 0;
5787 entered_regionview = 0;
5789 last_update_frame = 0;
5792 playhead_cursor->hide ();
5794 /* rip everything out of the list displays */
5798 _route_groups->clear ();
5800 /* do this first so that deleting a track doesn't reset cms to null
5801 and thus cause a leak.
5804 if (current_mixer_strip) {
5805 if (current_mixer_strip->get_parent() != 0) {
5806 global_hpacker.remove (*current_mixer_strip);
5808 delete current_mixer_strip;
5809 current_mixer_strip = 0;
5812 /* delete all trackviews */
5814 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5817 track_views.clear ();
5819 nudge_clock->set_session (0);
5821 editor_list_button.set_active(false);
5822 editor_list_button.set_sensitive(false);
5824 /* clear tempo/meter rulers */
5825 remove_metric_marks ();
5827 clear_marker_display ();
5829 stop_step_editing ();
5833 /* get rid of any existing editor mixer strip */
5835 WindowTitle title(Glib::get_application_name());
5836 title += _("Editor");
5838 own_window()->set_title (title.get_string());
5841 SessionHandlePtr::session_going_away ();
5845 Editor::trigger_script (int i)
5847 LuaInstance::instance()-> call_action (i);
5851 Editor::set_script_action_name (int i, const std::string& n)
5853 string const a = string_compose (X_("script-action-%1"), i + 1);
5854 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5857 act->set_label (string_compose (_("Unset #%1"), i + 1));
5858 act->set_tooltip (_("no action bound"));
5859 act->set_sensitive (false);
5862 act->set_tooltip (n);
5863 act->set_sensitive (true);
5865 KeyEditor::UpdateBindings ();
5869 Editor::show_editor_list (bool yn)
5872 _editor_list_vbox.show ();
5874 _editor_list_vbox.hide ();
5879 Editor::change_region_layering_order (bool from_context_menu)
5881 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5883 if (!clicked_routeview) {
5884 if (layering_order_editor) {
5885 layering_order_editor->hide ();
5890 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5896 boost::shared_ptr<Playlist> pl = track->playlist();
5902 if (layering_order_editor == 0) {
5903 layering_order_editor = new RegionLayeringOrderEditor (*this);
5906 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5907 layering_order_editor->maybe_present ();
5911 Editor::update_region_layering_order_editor ()
5913 if (layering_order_editor && layering_order_editor->is_visible ()) {
5914 change_region_layering_order (true);
5919 Editor::setup_fade_images ()
5921 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5922 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5923 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5924 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5925 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5927 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5928 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5929 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5930 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5931 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5933 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5934 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5935 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5936 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5937 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5939 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5940 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5941 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5942 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5943 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5947 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5949 Editor::action_menu_item (std::string const & name)
5951 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5954 return *manage (a->create_menu_item ());
5958 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5960 EventBox* b = manage (new EventBox);
5961 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5962 Label* l = manage (new Label (name));
5966 _the_notebook.append_page (widget, *b);
5970 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5972 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5973 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5976 if (ev->type == GDK_2BUTTON_PRESS) {
5978 /* double-click on a notebook tab shrinks or expands the notebook */
5980 if (_notebook_shrunk) {
5981 if (pre_notebook_shrink_pane_width) {
5982 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
5984 _notebook_shrunk = false;
5986 pre_notebook_shrink_pane_width = edit_pane.get_divider();
5988 /* this expands the LHS of the edit pane to cover the notebook
5989 PAGE but leaves the tabs visible.
5991 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
5992 _notebook_shrunk = true;
6000 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6002 using namespace Menu_Helpers;
6004 MenuList& items = _control_point_context_menu.items ();
6007 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6008 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6009 if (!can_remove_control_point (item)) {
6010 items.back().set_sensitive (false);
6013 _control_point_context_menu.popup (event->button.button, event->button.time);
6017 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6019 using namespace Menu_Helpers;
6021 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6026 /* We need to get the selection here and pass it to the operations, since
6027 popping up the menu will cause a region leave event which clears
6028 entered_regionview. */
6030 MidiRegionView& mrv = note->region_view();
6031 const RegionSelection rs = get_regions_from_selection_and_entered ();
6032 const uint32_t sel_size = mrv.selection_size ();
6034 MenuList& items = _note_context_menu.items();
6038 items.push_back(MenuElem(_("Delete"),
6039 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6042 items.push_back(MenuElem(_("Edit..."),
6043 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6044 if (sel_size != 1) {
6045 items.back().set_sensitive (false);
6048 items.push_back(MenuElem(_("Transpose..."),
6049 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6052 items.push_back(MenuElem(_("Legatize"),
6053 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6055 items.back().set_sensitive (false);
6058 items.push_back(MenuElem(_("Quantize..."),
6059 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6061 items.push_back(MenuElem(_("Remove Overlap"),
6062 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6064 items.back().set_sensitive (false);
6067 items.push_back(MenuElem(_("Transform..."),
6068 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6070 _note_context_menu.popup (event->button.button, event->button.time);
6074 Editor::zoom_vertical_modifier_released()
6076 _stepping_axis_view = 0;
6080 Editor::ui_parameter_changed (string parameter)
6082 if (parameter == "icon-set") {
6083 while (!_cursor_stack.empty()) {
6084 _cursor_stack.pop_back();
6086 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6087 _cursor_stack.push_back(_cursors->grabber);
6088 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6089 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6091 } else if (parameter == "draggable-playhead") {
6092 if (_verbose_cursor) {
6093 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6099 Editor::use_own_window (bool and_fill_it)
6101 bool new_window = !own_window();
6103 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6105 if (win && new_window) {
6106 win->set_name ("EditorWindow");
6108 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6110 // win->signal_realize().connect (*this, &Editor::on_realize);
6111 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6112 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6113 win->set_data ("ardour-bindings", bindings);
6118 DisplaySuspender ds;
6119 contents().show_all ();
6121 /* XXX: this is a bit unfortunate; it would probably
6122 be nicer if we could just call show () above rather
6123 than needing the show_all ()
6126 /* re-hide stuff if necessary */
6127 editor_list_button_toggled ();
6128 parameter_changed ("show-summary");
6129 parameter_changed ("show-group-tabs");
6130 parameter_changed ("show-zoom-tools");
6132 /* now reset all audio_time_axis heights, because widgets might need
6138 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6139 tv = (static_cast<TimeAxisView*>(*i));
6140 tv->reset_height ();
6143 if (current_mixer_strip) {
6144 current_mixer_strip->hide_things ();
6145 current_mixer_strip->parameter_changed ("mixer-element-visibility");