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/eventboxext.h"
61 #include "gtkmm2ext/grouped_buttons.h"
62 #include "gtkmm2ext/gtk_ui.h"
63 #include <gtkmm2ext/keyboard.h>
64 #include "gtkmm2ext/utils.h"
65 #include "gtkmm2ext/window_title.h"
66 #include "gtkmm2ext/choice.h"
67 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
69 #include "ardour/analysis_graph.h"
70 #include "ardour/audio_track.h"
71 #include "ardour/audioengine.h"
72 #include "ardour/audioregion.h"
73 #include "ardour/lmath.h"
74 #include "ardour/location.h"
75 #include "ardour/profile.h"
76 #include "ardour/route.h"
77 #include "ardour/route_group.h"
78 #include "ardour/session_playlists.h"
79 #include "ardour/tempo.h"
80 #include "ardour/utils.h"
81 #include "ardour/vca_manager.h"
82 #include "ardour/vca.h"
84 #include "canvas/debug.h"
85 #include "canvas/text.h"
87 #include "control_protocol/control_protocol.h"
90 #include "analysis_window.h"
91 #include "ardour_spacer.h"
92 #include "audio_clock.h"
93 #include "audio_region_view.h"
94 #include "audio_streamview.h"
95 #include "audio_time_axis.h"
96 #include "automation_time_axis.h"
97 #include "bundle_manager.h"
98 #include "crossfade_edit.h"
101 #include "editing_convert.h"
103 #include "editor_cursors.h"
104 #include "editor_drag.h"
105 #include "editor_group_tabs.h"
106 #include "editor_locations.h"
107 #include "editor_regions.h"
108 #include "editor_route_groups.h"
109 #include "editor_routes.h"
110 #include "editor_snapshots.h"
111 #include "editor_summary.h"
112 #include "enums_convert.h"
113 #include "export_report.h"
114 #include "global_port_matrix.h"
115 #include "gui_object.h"
116 #include "gui_thread.h"
117 #include "keyboard.h"
118 #include "luainstance.h"
120 #include "midi_region_view.h"
121 #include "midi_time_axis.h"
122 #include "mixer_strip.h"
123 #include "mixer_ui.h"
124 #include "mouse_cursors.h"
125 #include "note_base.h"
126 #include "playlist_selector.h"
127 #include "public_editor.h"
128 #include "quantize_dialog.h"
129 #include "region_layering_order_editor.h"
130 #include "rgb_macros.h"
131 #include "rhythm_ferret.h"
132 #include "route_sorter.h"
133 #include "selection.h"
134 #include "simple_progress_dialog.h"
136 #include "tempo_lines.h"
137 #include "time_axis_view.h"
138 #include "time_info_box.h"
140 #include "tooltips.h"
141 #include "ui_config.h"
143 #include "vca_time_axis.h"
144 #include "verbose_cursor.h"
146 #include "pbd/i18n.h"
149 using namespace ARDOUR;
150 using namespace ARDOUR_UI_UTILS;
153 using namespace Glib;
154 using namespace Gtkmm2ext;
155 using namespace Editing;
157 using PBD::internationalize;
159 using Gtkmm2ext::Keyboard;
161 double Editor::timebar_height = 15.0;
163 static const gchar *_snap_type_strings[] = {
197 static const gchar *_snap_mode_strings[] = {
204 static const gchar *_edit_point_strings[] = {
211 static const gchar *_edit_mode_strings[] = {
219 static const gchar *_zoom_focus_strings[] = {
229 #ifdef USE_RUBBERBAND
230 static const gchar *_rb_opt_strings[] = {
233 N_("Balanced multitimbral mixture"),
234 N_("Unpitched percussion with stable notes"),
235 N_("Crisp monophonic instrumental"),
236 N_("Unpitched solo percussion"),
237 N_("Resample without preserving pitch"),
242 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
245 : PublicEditor (global_hpacker)
246 , editor_mixer_strip_width (Wide)
247 , constructed (false)
248 , _playlist_selector (0)
250 , no_save_visual (false)
252 , samples_per_pixel (2048)
253 , zoom_focus (ZoomFocusPlayhead)
254 , mouse_mode (MouseObject)
255 , pre_internal_snap_type (SnapToBeat)
256 , pre_internal_snap_mode (SnapOff)
257 , internal_snap_type (SnapToBeat)
258 , internal_snap_mode (SnapOff)
259 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
260 , _notebook_shrunk (false)
261 , location_marker_color (0)
262 , location_range_color (0)
263 , location_loop_color (0)
264 , location_punch_color (0)
265 , location_cd_marker_color (0)
267 , _show_marker_lines (false)
268 , clicked_axisview (0)
269 , clicked_routeview (0)
270 , clicked_regionview (0)
271 , clicked_selection (0)
272 , clicked_control_point (0)
273 , button_release_can_deselect (true)
274 , _mouse_changed_selection (false)
275 , region_edit_menu_split_item (0)
276 , region_edit_menu_split_multichannel_item (0)
277 , track_region_edit_playlist_menu (0)
278 , track_edit_playlist_submenu (0)
279 , track_selection_edit_playlist_submenu (0)
280 , _popup_region_menu_item (0)
282 , _track_canvas_viewport (0)
283 , within_track_canvas (false)
284 , _verbose_cursor (0)
288 , range_marker_group (0)
289 , transport_marker_group (0)
290 , cd_marker_group (0)
291 , _time_markers_group (0)
292 , hv_scroll_group (0)
294 , cursor_scroll_group (0)
295 , no_scroll_group (0)
296 , _trackview_group (0)
297 , _drag_motion_group (0)
298 , _canvas_drop_zone (0)
299 , no_ruler_shown_update (false)
300 , ruler_grabbed_widget (0)
302 , minsec_mark_interval (0)
303 , minsec_mark_modulo (0)
305 , timecode_mark_modulo (0)
306 , timecode_nmarks (0)
307 , _samples_ruler_interval (0)
310 , bbt_bar_helper_on (0)
311 , bbt_accent_modulo (0)
316 , visible_timebars (0)
317 , editor_ruler_menu (0)
321 , range_marker_bar (0)
322 , transport_marker_bar (0)
324 , minsec_label (_("Mins:Secs"))
325 , bbt_label (_("Bars:Beats"))
326 , timecode_label (_("Timecode"))
327 , samples_label (_("Samples"))
328 , tempo_label (_("Tempo"))
329 , meter_label (_("Meter"))
330 , mark_label (_("Location Markers"))
331 , range_mark_label (_("Range Markers"))
332 , transport_mark_label (_("Loop/Punch Ranges"))
333 , cd_mark_label (_("CD Markers"))
334 , videotl_label (_("Video Timeline"))
336 , playhead_cursor (0)
337 , edit_packer (4, 4, true)
338 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
339 , horizontal_adjustment (0.0, 0.0, 1e16)
340 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
341 , controls_layout (unused_adjustment, vertical_adjustment)
342 , _scroll_callbacks (0)
343 , _visible_canvas_width (0)
344 , _visible_canvas_height (0)
345 , _full_canvas_height (0)
346 , edit_controls_left_menu (0)
347 , edit_controls_right_menu (0)
348 , _last_update_time (0)
349 , _err_screen_engine (0)
350 , cut_buffer_start (0)
351 , cut_buffer_length (0)
352 , button_bindings (0)
356 , current_interthread_info (0)
357 , analysis_window (0)
358 , select_new_marker (false)
360 , scrubbing_direction (0)
361 , scrub_reversals (0)
362 , scrub_reverse_distance (0)
363 , have_pending_keyboard_selection (false)
364 , pending_keyboard_selection_start (0)
365 , _snap_type (SnapToBeat)
366 , _snap_mode (SnapOff)
367 , snap_threshold (5.0)
368 , ignore_gui_changes (false)
369 , _drags (new DragManager (this))
371 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
372 , _dragging_playhead (false)
373 , _dragging_edit_point (false)
374 , _show_measures (true)
375 , _follow_playhead (true)
376 , _stationary_playhead (false)
379 , global_rect_group (0)
380 , time_line_group (0)
381 , tempo_marker_menu (0)
382 , meter_marker_menu (0)
384 , range_marker_menu (0)
385 , transport_marker_menu (0)
386 , new_transport_marker_menu (0)
388 , marker_menu_item (0)
389 , bbt_beat_subdivision (4)
390 , _visible_track_count (-1)
391 , toolbar_selection_clock_table (2,3)
392 , automation_mode_button (_("mode"))
393 , selection (new Selection (this))
394 , cut_buffer (new Selection (this))
395 , _selection_memento (new SelectionMemento())
396 , _all_region_actions_sensitized (false)
397 , _ignore_region_action (false)
398 , _last_region_menu_was_main (false)
399 , _track_selection_change_without_scroll (false)
400 , cd_marker_bar_drag_rect (0)
401 , range_bar_drag_rect (0)
402 , transport_bar_drag_rect (0)
403 , transport_bar_range_rect (0)
404 , transport_bar_preroll_rect (0)
405 , transport_bar_postroll_rect (0)
406 , transport_loop_range_rect (0)
407 , transport_punch_range_rect (0)
408 , transport_punchin_line (0)
409 , transport_punchout_line (0)
410 , transport_preroll_rect (0)
411 , transport_postroll_rect (0)
413 , rubberband_rect (0)
419 , autoscroll_horizontal_allowed (false)
420 , autoscroll_vertical_allowed (false)
422 , autoscroll_widget (0)
423 , show_gain_after_trim (false)
424 , selection_op_cmd_depth (0)
425 , selection_op_history_it (0)
426 , no_save_instant (false)
428 , current_mixer_strip (0)
429 , show_editor_mixer_when_tracks_arrive (false)
430 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
431 , current_stepping_trackview (0)
432 , last_track_height_step_timestamp (0)
434 , entered_regionview (0)
435 , clear_entered_track (false)
436 , _edit_point (EditAtMouse)
437 , meters_running (false)
439 , _have_idled (false)
440 , resize_idle_id (-1)
441 , _pending_resize_amount (0)
442 , _pending_resize_view (0)
443 , _pending_locate_request (false)
444 , _pending_initial_locate (false)
448 , layering_order_editor (0)
449 , _last_cut_copy_source_track (0)
450 , _region_selection_change_updates_region_list (true)
452 , _following_mixer_selection (false)
453 , _control_point_toggled_on_press (false)
454 , _stepping_axis_view (0)
455 , quantize_dialog (0)
456 , _main_menu_disabler (0)
457 , myactions (X_("editor"))
459 /* we are a singleton */
461 PublicEditor::_instance = this;
465 last_event_time.tv_sec = 0;
466 last_event_time.tv_usec = 0;
468 selection_op_history.clear();
471 snap_type_strings = I18N (_snap_type_strings);
472 snap_mode_strings = I18N (_snap_mode_strings);
473 zoom_focus_strings = I18N (_zoom_focus_strings);
474 edit_mode_strings = I18N (_edit_mode_strings);
475 edit_point_strings = I18N (_edit_point_strings);
476 #ifdef USE_RUBBERBAND
477 rb_opt_strings = I18N (_rb_opt_strings);
481 build_edit_mode_menu();
482 build_zoom_focus_menu();
483 build_track_count_menu();
484 build_snap_mode_menu();
485 build_snap_type_menu();
486 build_edit_point_menu();
488 location_marker_color = UIConfiguration::instance().color ("location marker");
489 location_range_color = UIConfiguration::instance().color ("location range");
490 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
491 location_loop_color = UIConfiguration::instance().color ("location loop");
492 location_punch_color = UIConfiguration::instance().color ("location punch");
494 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
496 TimeAxisView::setup_sizes ();
497 ArdourMarker::setup_sizes (timebar_height);
498 TempoCurve::setup_sizes (timebar_height);
500 bbt_label.set_name ("EditorRulerLabel");
501 bbt_label.set_size_request (-1, (int)timebar_height);
502 bbt_label.set_alignment (1.0, 0.5);
503 bbt_label.set_padding (5,0);
505 bbt_label.set_no_show_all();
506 minsec_label.set_name ("EditorRulerLabel");
507 minsec_label.set_size_request (-1, (int)timebar_height);
508 minsec_label.set_alignment (1.0, 0.5);
509 minsec_label.set_padding (5,0);
510 minsec_label.hide ();
511 minsec_label.set_no_show_all();
512 timecode_label.set_name ("EditorRulerLabel");
513 timecode_label.set_size_request (-1, (int)timebar_height);
514 timecode_label.set_alignment (1.0, 0.5);
515 timecode_label.set_padding (5,0);
516 timecode_label.hide ();
517 timecode_label.set_no_show_all();
518 samples_label.set_name ("EditorRulerLabel");
519 samples_label.set_size_request (-1, (int)timebar_height);
520 samples_label.set_alignment (1.0, 0.5);
521 samples_label.set_padding (5,0);
522 samples_label.hide ();
523 samples_label.set_no_show_all();
525 tempo_label.set_name ("EditorRulerLabel");
526 tempo_label.set_size_request (-1, (int)timebar_height);
527 tempo_label.set_alignment (1.0, 0.5);
528 tempo_label.set_padding (5,0);
530 tempo_label.set_no_show_all();
532 meter_label.set_name ("EditorRulerLabel");
533 meter_label.set_size_request (-1, (int)timebar_height);
534 meter_label.set_alignment (1.0, 0.5);
535 meter_label.set_padding (5,0);
537 meter_label.set_no_show_all();
539 if (Profile->get_trx()) {
540 mark_label.set_text (_("Markers"));
542 mark_label.set_name ("EditorRulerLabel");
543 mark_label.set_size_request (-1, (int)timebar_height);
544 mark_label.set_alignment (1.0, 0.5);
545 mark_label.set_padding (5,0);
547 mark_label.set_no_show_all();
549 cd_mark_label.set_name ("EditorRulerLabel");
550 cd_mark_label.set_size_request (-1, (int)timebar_height);
551 cd_mark_label.set_alignment (1.0, 0.5);
552 cd_mark_label.set_padding (5,0);
553 cd_mark_label.hide();
554 cd_mark_label.set_no_show_all();
556 videotl_bar_height = 4;
557 videotl_label.set_name ("EditorRulerLabel");
558 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
559 videotl_label.set_alignment (1.0, 0.5);
560 videotl_label.set_padding (5,0);
561 videotl_label.hide();
562 videotl_label.set_no_show_all();
564 range_mark_label.set_name ("EditorRulerLabel");
565 range_mark_label.set_size_request (-1, (int)timebar_height);
566 range_mark_label.set_alignment (1.0, 0.5);
567 range_mark_label.set_padding (5,0);
568 range_mark_label.hide();
569 range_mark_label.set_no_show_all();
571 transport_mark_label.set_name ("EditorRulerLabel");
572 transport_mark_label.set_size_request (-1, (int)timebar_height);
573 transport_mark_label.set_alignment (1.0, 0.5);
574 transport_mark_label.set_padding (5,0);
575 transport_mark_label.hide();
576 transport_mark_label.set_no_show_all();
578 initialize_canvas ();
580 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
582 _summary = new EditorSummary (this);
584 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
586 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
588 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
589 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
591 edit_controls_vbox.set_spacing (0);
592 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
593 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
595 HBox* h = manage (new HBox);
596 _group_tabs = new EditorGroupTabs (this);
597 if (!ARDOUR::Profile->get_trx()) {
598 h->pack_start (*_group_tabs, PACK_SHRINK);
600 h->pack_start (edit_controls_vbox);
601 controls_layout.add (*h);
603 controls_layout.set_name ("EditControlsBase");
604 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
605 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
606 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
608 _cursors = new MouseCursors;
609 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
610 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
612 /* Push default cursor to ever-present bottom of cursor stack. */
613 push_canvas_cursor(_cursors->grabber);
615 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
617 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
618 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
619 pad_line_1->set_outline_color (0xFF0000FF);
625 edit_packer.set_col_spacings (0);
626 edit_packer.set_row_spacings (0);
627 edit_packer.set_homogeneous (false);
628 edit_packer.set_border_width (0);
629 edit_packer.set_name ("EditorWindow");
631 time_bars_event_box.add (time_bars_vbox);
632 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
633 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
635 /* labels for the time bars */
636 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
638 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
640 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
642 bottom_hbox.set_border_width (2);
643 bottom_hbox.set_spacing (3);
645 _route_groups = new EditorRouteGroups (this);
646 _routes = new EditorRoutes (this);
647 _regions = new EditorRegions (this);
648 _snapshots = new EditorSnapshots (this);
649 _locations = new EditorLocations (this);
650 _time_info_box = new TimeInfoBox ("EditorTimeInfo", true);
652 /* these are static location signals */
654 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
655 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
656 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
658 add_notebook_page (_("Regions"), _regions->widget ());
659 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
660 add_notebook_page (_("Snapshots"), _snapshots->widget ());
661 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
662 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
664 _the_notebook.set_show_tabs (true);
665 _the_notebook.set_scrollable (true);
666 _the_notebook.popup_disable ();
667 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
668 _the_notebook.show_all ();
670 _notebook_shrunk = false;
673 /* Pick up some settings we need to cache, early */
675 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
678 settings->get_property ("notebook-shrunk", _notebook_shrunk);
681 editor_summary_pane.set_check_divider_position (true);
682 editor_summary_pane.add (edit_packer);
684 Button* summary_arrows_left_left = manage (new Button);
685 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
686 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
687 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
689 Button* summary_arrows_left_right = manage (new Button);
690 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
691 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
692 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
694 VBox* summary_arrows_left = manage (new VBox);
695 summary_arrows_left->pack_start (*summary_arrows_left_left);
696 summary_arrows_left->pack_start (*summary_arrows_left_right);
698 Button* summary_arrows_right_up = manage (new Button);
699 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
700 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
701 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
703 Button* summary_arrows_right_down = manage (new Button);
704 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
705 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
706 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
708 VBox* summary_arrows_right = manage (new VBox);
709 summary_arrows_right->pack_start (*summary_arrows_right_up);
710 summary_arrows_right->pack_start (*summary_arrows_right_down);
712 Frame* summary_frame = manage (new Frame);
713 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
715 summary_frame->add (*_summary);
716 summary_frame->show ();
718 _summary_hbox.pack_start (*summary_arrows_left, false, false);
719 _summary_hbox.pack_start (*summary_frame, true, true);
720 _summary_hbox.pack_start (*summary_arrows_right, false, false);
722 if (!ARDOUR::Profile->get_trx()) {
723 editor_summary_pane.add (_summary_hbox);
726 edit_pane.set_check_divider_position (true);
727 edit_pane.add (editor_summary_pane);
728 if (!ARDOUR::Profile->get_trx()) {
729 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
730 _editor_list_vbox.pack_start (_the_notebook);
731 edit_pane.add (_editor_list_vbox);
732 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
735 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
736 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
743 if (!settings || !settings->get_property ("edit-horizontal-pane-pos", fract) || fract > 1.0) {
744 /* initial allocation is 90% to canvas, 10% to notebook */
747 edit_pane.set_divider (0, fract);
749 if (!settings || !settings->get_property ("edit-vertical-pane-pos", fract) || fract > 1.0) {
750 /* initial allocation is 90% to canvas, 10% to summary */
753 editor_summary_pane.set_divider (0, fract);
756 global_vpacker.set_spacing (2);
757 global_vpacker.set_border_width (0);
759 //the next three EventBoxes provide the ability for their child widgets to have a background color. That is all.
761 Gtk::EventBox* ebox = manage (new Gtk::EventBox); //a themeable box
762 ebox->set_name("EditorWindow");
763 ebox->add (toolbar_hbox);
765 Gtk::EventBox* epane_box = manage (new Gtkmm2ext::EventBoxExt); //a themeable box
766 epane_box->set_name("EditorWindow");
767 epane_box->add (edit_pane);
769 Gtk::EventBox* epane_box2 = manage (new Gtkmm2ext::EventBoxExt); //a themeable box
770 epane_box2->set_name("EditorWindow");
771 epane_box2->add (global_vpacker);
773 global_vpacker.pack_start (*ebox, false, false);
774 global_vpacker.pack_start (*epane_box, true, true);
775 global_hpacker.pack_start (*epane_box2, true, true);
777 /* need to show the "contents" widget so that notebook will show if tab is switched to
780 global_hpacker.show ();
782 /* register actions now so that set_state() can find them and set toggles/checks etc */
789 _playlist_selector = new PlaylistSelector();
790 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
792 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
796 nudge_forward_button.set_name ("nudge button");
797 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
799 nudge_backward_button.set_name ("nudge button");
800 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
802 fade_context_menu.set_name ("ArdourContextMenu");
804 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
806 /* allow external control surfaces/protocols to do various things */
808 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
809 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
810 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
811 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
812 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
813 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
814 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
815 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
816 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
817 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
818 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
819 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
820 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
821 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
823 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
824 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
825 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
826 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
827 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
829 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
833 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
835 /* problematic: has to return a value and thus cannot be x-thread */
837 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
839 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
840 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
842 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
844 _ignore_region_action = false;
845 _last_region_menu_was_main = false;
846 _popup_region_menu_item = 0;
848 _show_marker_lines = false;
850 /* Button bindings */
852 button_bindings = new Bindings ("editor-mouse");
854 XMLNode* node = button_settings();
856 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
857 button_bindings->load_operation (**i);
863 /* grab current parameter state */
864 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
865 UIConfiguration::instance().map_parameters (pc);
867 setup_fade_images ();
874 delete button_bindings;
876 delete _route_groups;
877 delete _track_canvas_viewport;
880 delete _verbose_cursor;
881 delete quantize_dialog;
887 delete _playlist_selector;
888 delete _time_info_box;
893 LuaInstance::destroy_instance ();
895 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
898 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_in_images.begin(); i != _xfade_in_images.end (); ++i) {
901 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_out_images.begin(); i != _xfade_out_images.end (); ++i) {
907 Editor::button_settings () const
909 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
910 XMLNode* node = find_named_node (*settings, X_("Buttons"));
913 node = new XMLNode (X_("Buttons"));
920 Editor::get_smart_mode () const
922 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
926 Editor::catch_vanishing_regionview (RegionView *rv)
928 /* note: the selection will take care of the vanishing
929 audioregionview by itself.
932 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
936 if (clicked_regionview == rv) {
937 clicked_regionview = 0;
940 if (entered_regionview == rv) {
941 set_entered_regionview (0);
944 if (!_all_region_actions_sensitized) {
945 sensitize_all_region_actions (true);
950 Editor::set_entered_regionview (RegionView* rv)
952 if (rv == entered_regionview) {
956 if (entered_regionview) {
957 entered_regionview->exited ();
960 entered_regionview = rv;
962 if (entered_regionview != 0) {
963 entered_regionview->entered ();
966 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
967 /* This RegionView entry might have changed what region actions
968 are allowed, so sensitize them all in case a key is pressed.
970 sensitize_all_region_actions (true);
975 Editor::set_entered_track (TimeAxisView* tav)
978 entered_track->exited ();
984 entered_track->entered ();
989 Editor::instant_save ()
991 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
996 _session->add_instant_xml(get_state());
998 Config->add_instant_xml(get_state());
1003 Editor::control_vertical_zoom_in_all ()
1005 tav_zoom_smooth (false, true);
1009 Editor::control_vertical_zoom_out_all ()
1011 tav_zoom_smooth (true, true);
1015 Editor::control_vertical_zoom_in_selected ()
1017 tav_zoom_smooth (false, false);
1021 Editor::control_vertical_zoom_out_selected ()
1023 tav_zoom_smooth (true, false);
1027 Editor::control_view (uint32_t view)
1029 goto_visual_state (view);
1033 Editor::control_unselect ()
1035 selection->clear_tracks ();
1039 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1041 TimeAxisView* tav = axis_view_from_stripable (s);
1045 case Selection::Add:
1046 selection->add (tav);
1048 case Selection::Toggle:
1049 selection->toggle (tav);
1051 case Selection::Extend:
1053 case Selection::Set:
1054 selection->set (tav);
1058 selection->clear_tracks ();
1063 Editor::control_step_tracks_up ()
1065 scroll_tracks_up_line ();
1069 Editor::control_step_tracks_down ()
1071 scroll_tracks_down_line ();
1075 Editor::control_scroll (float fraction)
1077 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1083 double step = fraction * current_page_samples();
1086 _control_scroll_target is an optional<T>
1088 it acts like a pointer to an framepos_t, with
1089 a operator conversion to boolean to check
1090 that it has a value could possibly use
1091 playhead_cursor->current_frame to store the
1092 value and a boolean in the class to know
1093 when it's out of date
1096 if (!_control_scroll_target) {
1097 _control_scroll_target = _session->transport_frame();
1098 _dragging_playhead = true;
1101 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1102 *_control_scroll_target = 0;
1103 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1104 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1106 *_control_scroll_target += (framepos_t) trunc (step);
1109 /* move visuals, we'll catch up with it later */
1111 playhead_cursor->set_position (*_control_scroll_target);
1112 UpdateAllTransportClocks (*_control_scroll_target);
1114 if (*_control_scroll_target > (current_page_samples() / 2)) {
1115 /* try to center PH in window */
1116 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1122 Now we do a timeout to actually bring the session to the right place
1123 according to the playhead. This is to avoid reading disk buffers on every
1124 call to control_scroll, which is driven by ScrollTimeline and therefore
1125 probably by a control surface wheel which can generate lots of events.
1127 /* cancel the existing timeout */
1129 control_scroll_connection.disconnect ();
1131 /* add the next timeout */
1133 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1137 Editor::deferred_control_scroll (framepos_t /*target*/)
1139 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1140 // reset for next stream
1141 _control_scroll_target = boost::none;
1142 _dragging_playhead = false;
1147 Editor::access_action (std::string action_group, std::string action_item)
1153 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1156 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1164 Editor::on_realize ()
1168 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1169 start_lock_event_timing ();
1174 Editor::start_lock_event_timing ()
1176 /* check if we should lock the GUI every 30 seconds */
1178 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1182 Editor::generic_event_handler (GdkEvent* ev)
1185 case GDK_BUTTON_PRESS:
1186 case GDK_BUTTON_RELEASE:
1187 case GDK_MOTION_NOTIFY:
1189 case GDK_KEY_RELEASE:
1190 if (contents().is_mapped()) {
1191 gettimeofday (&last_event_time, 0);
1195 case GDK_LEAVE_NOTIFY:
1196 switch (ev->crossing.detail) {
1197 case GDK_NOTIFY_UNKNOWN:
1198 case GDK_NOTIFY_INFERIOR:
1199 case GDK_NOTIFY_ANCESTOR:
1201 case GDK_NOTIFY_VIRTUAL:
1202 case GDK_NOTIFY_NONLINEAR:
1203 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1204 /* leaving window, so reset focus, thus ending any and
1205 all text entry operations.
1207 ARDOUR_UI::instance()->reset_focus (&contents());
1220 Editor::lock_timeout_callback ()
1222 struct timeval now, delta;
1224 gettimeofday (&now, 0);
1226 timersub (&now, &last_event_time, &delta);
1228 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1230 /* don't call again. Returning false will effectively
1231 disconnect us from the timer callback.
1233 unlock() will call start_lock_event_timing() to get things
1243 Editor::map_position_change (framepos_t frame)
1245 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1247 if (_session == 0) {
1251 if (_follow_playhead) {
1252 center_screen (frame);
1255 playhead_cursor->set_position (frame);
1259 Editor::center_screen (framepos_t frame)
1261 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1263 /* if we're off the page, then scroll.
1266 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1267 center_screen_internal (frame, page);
1272 Editor::center_screen_internal (framepos_t frame, float page)
1277 frame -= (framepos_t) page;
1282 reset_x_origin (frame);
1287 Editor::update_title ()
1289 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1291 if (!own_window()) {
1296 bool dirty = _session->dirty();
1298 string session_name;
1300 if (_session->snap_name() != _session->name()) {
1301 session_name = _session->snap_name();
1303 session_name = _session->name();
1307 session_name = "*" + session_name;
1310 WindowTitle title(session_name);
1311 title += S_("Window|Editor");
1312 title += Glib::get_application_name();
1313 own_window()->set_title (title.get_string());
1315 /* ::session_going_away() will have taken care of it */
1320 Editor::set_session (Session *t)
1322 SessionHandlePtr::set_session (t);
1328 _playlist_selector->set_session (_session);
1329 nudge_clock->set_session (_session);
1330 _summary->set_session (_session);
1331 _group_tabs->set_session (_session);
1332 _route_groups->set_session (_session);
1333 _regions->set_session (_session);
1334 _snapshots->set_session (_session);
1335 _routes->set_session (_session);
1336 _locations->set_session (_session);
1337 _time_info_box->set_session (_session);
1339 if (rhythm_ferret) {
1340 rhythm_ferret->set_session (_session);
1343 if (analysis_window) {
1344 analysis_window->set_session (_session);
1348 sfbrowser->set_session (_session);
1351 compute_fixed_ruler_scale ();
1353 /* Make sure we have auto loop and auto punch ranges */
1355 Location* loc = _session->locations()->auto_loop_location();
1357 loc->set_name (_("Loop"));
1360 loc = _session->locations()->auto_punch_location();
1363 loc->set_name (_("Punch"));
1366 refresh_location_display ();
1368 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1369 the selected Marker; this needs the LocationMarker list to be available.
1371 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1372 set_state (*node, Stateful::loading_state_version);
1374 /* catch up with the playhead */
1376 _session->request_locate (playhead_cursor->current_frame ());
1377 _pending_initial_locate = true;
1381 /* These signals can all be emitted by a non-GUI thread. Therefore the
1382 handlers for them must not attempt to directly interact with the GUI,
1383 but use PBD::Signal<T>::connect() which accepts an event loop
1384 ("context") where the handler will be asked to run.
1387 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1388 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1389 _session->TransportLooped.connect (_session_connections, invalidator (*this), boost::bind (&Editor::transport_looped, this), gui_context());
1390 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1391 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1392 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1393 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1394 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1395 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1396 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1397 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1398 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1399 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1400 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1401 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1402 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1404 playhead_cursor->show ();
1406 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1407 Config->map_parameters (pc);
1408 _session->config.map_parameters (pc);
1410 restore_ruler_visibility ();
1411 //tempo_map_changed (PropertyChange (0));
1412 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1414 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1415 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1418 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1419 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1422 switch (_snap_type) {
1423 case SnapToRegionStart:
1424 case SnapToRegionEnd:
1425 case SnapToRegionSync:
1426 case SnapToRegionBoundary:
1427 build_region_boundary_cache ();
1434 /* catch up on selection of stripables (other selection state is lost
1435 * when a session is closed
1440 _session->get_stripables (sl);
1441 for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
1442 if ((*s)->presentation_info().selected()) {
1443 RouteTimeAxisView* rtav = get_route_view_by_route_id ((*s)->id());
1445 tl.push_back (rtav);
1450 selection->set (tl);
1453 /* register for undo history */
1454 _session->register_with_memento_command_factory(id(), this);
1455 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1457 LuaInstance::instance()->set_session(_session);
1459 start_updating_meters ();
1463 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1465 using namespace Menu_Helpers;
1467 void (Editor::*emf)(FadeShape);
1468 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1471 images = &_xfade_in_images;
1472 emf = &Editor::set_fade_in_shape;
1474 images = &_xfade_out_images;
1475 emf = &Editor::set_fade_out_shape;
1480 _("Linear (for highly correlated material)"),
1481 *(*images)[FadeLinear],
1482 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1486 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1490 _("Constant power"),
1491 *(*images)[FadeConstantPower],
1492 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1495 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1500 *(*images)[FadeSymmetric],
1501 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1505 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1510 *(*images)[FadeSlow],
1511 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1514 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1519 *(*images)[FadeFast],
1520 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1523 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1526 /** Pop up a context menu for when the user clicks on a start crossfade */
1528 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1530 using namespace Menu_Helpers;
1531 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1536 MenuList& items (xfade_in_context_menu.items());
1539 if (arv->audio_region()->fade_in_active()) {
1540 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1542 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1545 items.push_back (SeparatorElem());
1546 fill_xfade_menu (items, true);
1548 xfade_in_context_menu.popup (button, time);
1551 /** Pop up a context menu for when the user clicks on an end crossfade */
1553 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1555 using namespace Menu_Helpers;
1556 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1561 MenuList& items (xfade_out_context_menu.items());
1564 if (arv->audio_region()->fade_out_active()) {
1565 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1567 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1570 items.push_back (SeparatorElem());
1571 fill_xfade_menu (items, false);
1573 xfade_out_context_menu.popup (button, time);
1577 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1579 using namespace Menu_Helpers;
1580 Menu* (Editor::*build_menu_function)();
1583 switch (item_type) {
1585 case RegionViewName:
1586 case RegionViewNameHighlight:
1587 case LeftFrameHandle:
1588 case RightFrameHandle:
1589 if (with_selection) {
1590 build_menu_function = &Editor::build_track_selection_context_menu;
1592 build_menu_function = &Editor::build_track_region_context_menu;
1597 if (with_selection) {
1598 build_menu_function = &Editor::build_track_selection_context_menu;
1600 build_menu_function = &Editor::build_track_context_menu;
1605 if (clicked_routeview->track()) {
1606 build_menu_function = &Editor::build_track_context_menu;
1608 build_menu_function = &Editor::build_track_bus_context_menu;
1613 /* probably shouldn't happen but if it does, we don't care */
1617 menu = (this->*build_menu_function)();
1618 menu->set_name ("ArdourContextMenu");
1620 /* now handle specific situations */
1622 switch (item_type) {
1624 case RegionViewName:
1625 case RegionViewNameHighlight:
1626 case LeftFrameHandle:
1627 case RightFrameHandle:
1628 if (!with_selection) {
1629 if (region_edit_menu_split_item) {
1630 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1631 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1633 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1636 if (region_edit_menu_split_multichannel_item) {
1637 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1638 region_edit_menu_split_multichannel_item->set_sensitive (true);
1640 region_edit_menu_split_multichannel_item->set_sensitive (false);
1653 /* probably shouldn't happen but if it does, we don't care */
1657 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1659 /* Bounce to disk */
1661 using namespace Menu_Helpers;
1662 MenuList& edit_items = menu->items();
1664 edit_items.push_back (SeparatorElem());
1666 switch (clicked_routeview->audio_track()->freeze_state()) {
1667 case AudioTrack::NoFreeze:
1668 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1671 case AudioTrack::Frozen:
1672 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1675 case AudioTrack::UnFrozen:
1676 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1682 if (item_type == StreamItem && clicked_routeview) {
1683 clicked_routeview->build_underlay_menu(menu);
1686 /* When the region menu is opened, we setup the actions so that they look right
1689 sensitize_the_right_region_actions (false);
1690 _last_region_menu_was_main = false;
1692 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1693 menu->popup (button, time);
1697 Editor::build_track_context_menu ()
1699 using namespace Menu_Helpers;
1701 MenuList& edit_items = track_context_menu.items();
1704 add_dstream_context_items (edit_items);
1705 return &track_context_menu;
1709 Editor::build_track_bus_context_menu ()
1711 using namespace Menu_Helpers;
1713 MenuList& edit_items = track_context_menu.items();
1716 add_bus_context_items (edit_items);
1717 return &track_context_menu;
1721 Editor::build_track_region_context_menu ()
1723 using namespace Menu_Helpers;
1724 MenuList& edit_items = track_region_context_menu.items();
1727 /* we've just cleared the track region context menu, so the menu that these
1728 two items were on will have disappeared; stop them dangling.
1730 region_edit_menu_split_item = 0;
1731 region_edit_menu_split_multichannel_item = 0;
1733 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1736 boost::shared_ptr<Track> tr;
1737 boost::shared_ptr<Playlist> pl;
1739 if ((tr = rtv->track())) {
1740 add_region_context_items (edit_items, tr);
1744 add_dstream_context_items (edit_items);
1746 return &track_region_context_menu;
1750 Editor::loudness_analyze_region_selection ()
1755 Selection& s (PublicEditor::instance ().get_selection ());
1756 RegionSelection ars = s.regions;
1757 ARDOUR::AnalysisGraph ag (_session);
1758 framecnt_t total_work = 0;
1760 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1761 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1765 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1768 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1769 total_work += arv->region ()->length ();
1772 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1774 ag.set_total_frames (total_work);
1775 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1778 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1779 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1783 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1787 ag.analyze_region (ar);
1790 if (!ag.canceled ()) {
1791 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1797 Editor::loudness_analyze_range_selection ()
1802 Selection& s (PublicEditor::instance ().get_selection ());
1803 TimeSelection ts = s.time;
1804 ARDOUR::AnalysisGraph ag (_session);
1805 framecnt_t total_work = 0;
1807 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1808 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1812 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1816 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1817 total_work += j->length ();
1821 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1823 ag.set_total_frames (total_work);
1824 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1827 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1828 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1832 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1836 ag.analyze_range (rui->route (), pl, ts);
1839 if (!ag.canceled ()) {
1840 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1846 Editor::spectral_analyze_region_selection ()
1848 if (analysis_window == 0) {
1849 analysis_window = new AnalysisWindow();
1852 analysis_window->set_session(_session);
1854 analysis_window->show_all();
1857 analysis_window->set_regionmode();
1858 analysis_window->analyze();
1860 analysis_window->present();
1864 Editor::spectral_analyze_range_selection()
1866 if (analysis_window == 0) {
1867 analysis_window = new AnalysisWindow();
1870 analysis_window->set_session(_session);
1872 analysis_window->show_all();
1875 analysis_window->set_rangemode();
1876 analysis_window->analyze();
1878 analysis_window->present();
1882 Editor::build_track_selection_context_menu ()
1884 using namespace Menu_Helpers;
1885 MenuList& edit_items = track_selection_context_menu.items();
1886 edit_items.clear ();
1888 add_selection_context_items (edit_items);
1889 // edit_items.push_back (SeparatorElem());
1890 // add_dstream_context_items (edit_items);
1892 return &track_selection_context_menu;
1896 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1898 using namespace Menu_Helpers;
1900 /* OK, stick the region submenu at the top of the list, and then add
1904 RegionSelection rs = get_regions_from_selection_and_entered ();
1906 string::size_type pos = 0;
1907 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1909 /* we have to hack up the region name because "_" has a special
1910 meaning for menu titles.
1913 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1914 menu_item_name.replace (pos, 1, "__");
1918 if (_popup_region_menu_item == 0) {
1919 _popup_region_menu_item = new MenuItem (menu_item_name);
1920 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1921 _popup_region_menu_item->show ();
1923 _popup_region_menu_item->set_label (menu_item_name);
1926 /* No layering allowed in later is higher layering model */
1927 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1928 if (act && Config->get_layer_model() == LaterHigher) {
1929 act->set_sensitive (false);
1931 act->set_sensitive (true);
1934 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1936 edit_items.push_back (*_popup_region_menu_item);
1937 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1938 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1940 edit_items.push_back (SeparatorElem());
1943 /** Add context menu items relevant to selection ranges.
1944 * @param edit_items List to add the items to.
1947 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1949 using namespace Menu_Helpers;
1951 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1952 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1954 edit_items.push_back (SeparatorElem());
1955 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1957 edit_items.push_back (SeparatorElem());
1958 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1959 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1961 edit_items.push_back (SeparatorElem());
1963 edit_items.push_back (
1965 _("Move Range Start to Previous Region Boundary"),
1966 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1970 edit_items.push_back (
1972 _("Move Range Start to Next Region Boundary"),
1973 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1977 edit_items.push_back (
1979 _("Move Range End to Previous Region Boundary"),
1980 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1984 edit_items.push_back (
1986 _("Move Range End to Next Region Boundary"),
1987 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1991 edit_items.push_back (SeparatorElem());
1992 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1993 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1995 edit_items.push_back (SeparatorElem());
1996 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1998 edit_items.push_back (SeparatorElem());
1999 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
2000 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
2001 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
2003 edit_items.push_back (SeparatorElem());
2004 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
2006 edit_items.push_back (SeparatorElem());
2007 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
2008 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
2010 edit_items.push_back (SeparatorElem());
2011 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
2012 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
2013 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
2014 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
2015 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
2016 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
2017 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2023 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2025 using namespace Menu_Helpers;
2029 Menu *play_menu = manage (new Menu);
2030 MenuList& play_items = play_menu->items();
2031 play_menu->set_name ("ArdourContextMenu");
2033 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2034 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2035 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2036 play_items.push_back (SeparatorElem());
2037 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2039 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2043 Menu *select_menu = manage (new Menu);
2044 MenuList& select_items = select_menu->items();
2045 select_menu->set_name ("ArdourContextMenu");
2047 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2048 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2049 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2050 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2051 select_items.push_back (SeparatorElem());
2052 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2053 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2054 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2055 select_items.push_back (SeparatorElem());
2056 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2057 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2058 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2059 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2060 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2061 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2062 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2064 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2068 Menu *cutnpaste_menu = manage (new Menu);
2069 MenuList& cutnpaste_items = cutnpaste_menu->items();
2070 cutnpaste_menu->set_name ("ArdourContextMenu");
2072 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2073 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2074 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2076 cutnpaste_items.push_back (SeparatorElem());
2078 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2079 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2081 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2083 /* Adding new material */
2085 edit_items.push_back (SeparatorElem());
2086 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2087 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2091 Menu *nudge_menu = manage (new Menu());
2092 MenuList& nudge_items = nudge_menu->items();
2093 nudge_menu->set_name ("ArdourContextMenu");
2095 edit_items.push_back (SeparatorElem());
2096 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2097 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2098 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2099 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2101 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2105 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2107 using namespace Menu_Helpers;
2111 Menu *play_menu = manage (new Menu);
2112 MenuList& play_items = play_menu->items();
2113 play_menu->set_name ("ArdourContextMenu");
2115 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2116 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2117 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2121 Menu *select_menu = manage (new Menu);
2122 MenuList& select_items = select_menu->items();
2123 select_menu->set_name ("ArdourContextMenu");
2125 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2126 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2127 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2128 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2129 select_items.push_back (SeparatorElem());
2130 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2131 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2132 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2133 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2135 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2139 Menu *cutnpaste_menu = manage (new Menu);
2140 MenuList& cutnpaste_items = cutnpaste_menu->items();
2141 cutnpaste_menu->set_name ("ArdourContextMenu");
2143 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2144 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2145 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2147 Menu *nudge_menu = manage (new Menu());
2148 MenuList& nudge_items = nudge_menu->items();
2149 nudge_menu->set_name ("ArdourContextMenu");
2151 edit_items.push_back (SeparatorElem());
2152 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2153 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2154 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2155 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2157 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2161 Editor::snap_type() const
2167 Editor::snap_musical() const
2169 switch (_snap_type) {
2170 case SnapToBeatDiv128:
2171 case SnapToBeatDiv64:
2172 case SnapToBeatDiv32:
2173 case SnapToBeatDiv28:
2174 case SnapToBeatDiv24:
2175 case SnapToBeatDiv20:
2176 case SnapToBeatDiv16:
2177 case SnapToBeatDiv14:
2178 case SnapToBeatDiv12:
2179 case SnapToBeatDiv10:
2180 case SnapToBeatDiv8:
2181 case SnapToBeatDiv7:
2182 case SnapToBeatDiv6:
2183 case SnapToBeatDiv5:
2184 case SnapToBeatDiv4:
2185 case SnapToBeatDiv3:
2186 case SnapToBeatDiv2:
2198 Editor::snap_mode() const
2204 Editor::set_snap_to (SnapType st)
2206 unsigned int snap_ind = (unsigned int)st;
2208 if (internal_editing()) {
2209 internal_snap_type = st;
2211 pre_internal_snap_type = st;
2216 if (snap_ind > snap_type_strings.size() - 1) {
2218 _snap_type = (SnapType)snap_ind;
2221 string str = snap_type_strings[snap_ind];
2223 if (str != snap_type_selector.get_text()) {
2224 snap_type_selector.set_text (str);
2229 switch (_snap_type) {
2230 case SnapToBeatDiv128:
2231 case SnapToBeatDiv64:
2232 case SnapToBeatDiv32:
2233 case SnapToBeatDiv28:
2234 case SnapToBeatDiv24:
2235 case SnapToBeatDiv20:
2236 case SnapToBeatDiv16:
2237 case SnapToBeatDiv14:
2238 case SnapToBeatDiv12:
2239 case SnapToBeatDiv10:
2240 case SnapToBeatDiv8:
2241 case SnapToBeatDiv7:
2242 case SnapToBeatDiv6:
2243 case SnapToBeatDiv5:
2244 case SnapToBeatDiv4:
2245 case SnapToBeatDiv3:
2246 case SnapToBeatDiv2: {
2247 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
2248 update_tempo_based_rulers ();
2252 case SnapToRegionStart:
2253 case SnapToRegionEnd:
2254 case SnapToRegionSync:
2255 case SnapToRegionBoundary:
2256 build_region_boundary_cache ();
2264 redisplay_tempo (false);
2266 SnapChanged (); /* EMIT SIGNAL */
2270 Editor::set_snap_mode (SnapMode mode)
2272 string str = snap_mode_strings[(int)mode];
2274 if (internal_editing()) {
2275 internal_snap_mode = mode;
2277 pre_internal_snap_mode = mode;
2282 if (str != snap_mode_selector.get_text ()) {
2283 snap_mode_selector.set_text (str);
2290 Editor::set_edit_point_preference (EditPoint ep, bool force)
2292 bool changed = (_edit_point != ep);
2295 if (Profile->get_mixbus())
2296 if (ep == EditAtSelectedMarker)
2297 ep = EditAtPlayhead;
2299 string str = edit_point_strings[(int)ep];
2300 if (str != edit_point_selector.get_text ()) {
2301 edit_point_selector.set_text (str);
2304 update_all_enter_cursors();
2306 if (!force && !changed) {
2310 const char* action=NULL;
2312 switch (_edit_point) {
2313 case EditAtPlayhead:
2314 action = "edit-at-playhead";
2316 case EditAtSelectedMarker:
2317 action = "edit-at-marker";
2320 action = "edit-at-mouse";
2324 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2326 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2330 bool in_track_canvas;
2332 if (!mouse_frame (foo, in_track_canvas)) {
2333 in_track_canvas = false;
2336 reset_canvas_action_sensitivity (in_track_canvas);
2337 sensitize_the_right_region_actions (false);
2343 Editor::set_state (const XMLNode& node, int version)
2346 PBD::Unwinder<bool> nsi (no_save_instant, true);
2350 Tabbable::set_state (node, version);
2353 if (_session && node.get_property ("playhead", ph_pos)) {
2355 playhead_cursor->set_position (ph_pos);
2357 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2358 playhead_cursor->set_position (0);
2361 playhead_cursor->set_position (0);
2364 node.get_property ("mixer-width", editor_mixer_strip_width);
2366 node.get_property ("zoom-focus", zoom_focus);
2367 zoom_focus_selection_done (zoom_focus);
2370 if (node.get_property ("zoom", z)) {
2371 /* older versions of ardour used floating point samples_per_pixel */
2372 reset_zoom (llrintf (z));
2374 reset_zoom (samples_per_pixel);
2378 if (node.get_property ("visible-track-count", cnt)) {
2379 set_visible_track_count (cnt);
2383 if (!node.get_property ("snap-to", snap_type)) {
2384 snap_type = _snap_type;
2386 set_snap_to (snap_type);
2389 if (node.get_property ("snap-mode", sm)) {
2390 snap_mode_selection_done(sm);
2391 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2392 * snap_mode_selection_done() will only mark an already active item as active
2393 * which does not trigger set_text().
2397 set_snap_mode (_snap_mode);
2400 node.get_property ("internal-snap-to", internal_snap_type);
2401 node.get_property ("internal-snap-mode", internal_snap_mode);
2402 node.get_property ("pre-internal-snap-to", pre_internal_snap_type);
2403 node.get_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2406 if (node.get_property ("mouse-mode", mm_str)) {
2407 MouseMode m = str2mousemode(mm_str);
2408 set_mouse_mode (m, true);
2410 set_mouse_mode (MouseObject, true);
2414 if (node.get_property ("left-frame", lf_pos)) {
2418 reset_x_origin (lf_pos);
2422 if (node.get_property ("y-origin", y_origin)) {
2423 reset_y_origin (y_origin);
2426 if (node.get_property ("join-object-range", yn)) {
2427 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2429 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2430 tact->set_active (!yn);
2431 tact->set_active (yn);
2433 set_mouse_mode(mouse_mode, true);
2437 if (node.get_property ("edit-point", ep)) {
2438 set_edit_point_preference (ep, true);
2440 set_edit_point_preference (_edit_point);
2443 node.get_property ("show-measures", _show_measures);
2445 if (node.get_property ("follow-playhead", yn)) {
2446 set_follow_playhead (yn);
2449 if (node.get_property ("stationary-playhead", yn)) {
2450 set_stationary_playhead (yn);
2453 RegionListSortType sort_type;
2454 if (node.get_property ("region-list-sort-type", sort_type)) {
2455 _regions->reset_sort_type (sort_type, true);
2458 if (node.get_property ("show-editor-mixer", yn)) {
2460 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2463 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2465 /* do it twice to force the change */
2467 tact->set_active (!yn);
2468 tact->set_active (yn);
2471 if (node.get_property ("show-editor-list", yn)) {
2473 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2476 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2478 /* do it twice to force the change */
2480 tact->set_active (!yn);
2481 tact->set_active (yn);
2485 if (node.get_property (X_("editor-list-page"), el_page)) {
2486 _the_notebook.set_current_page (el_page);
2489 if (node.get_property (X_("show-marker-lines"), yn)) {
2490 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2492 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2494 tact->set_active (!yn);
2495 tact->set_active (yn);
2498 XMLNodeList children = node.children ();
2499 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2500 selection->set_state (**i, Stateful::current_state_version);
2501 _regions->set_state (**i);
2502 _locations->set_state (**i);
2505 if (node.get_property ("maximised", yn)) {
2506 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2508 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2509 bool fs = tact && tact->get_active();
2511 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2515 framepos_t nudge_clock_value;
2516 if (node.get_property ("nudge-clock-value", nudge_clock_value)) {
2517 nudge_clock->set (nudge_clock_value);
2519 nudge_clock->set_mode (AudioClock::Timecode);
2520 nudge_clock->set (_session->frame_rate() * 5, true);
2525 * Not all properties may have been in XML, but
2526 * those that are linked to a private variable may need changing
2530 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2532 yn = _show_measures;
2533 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2534 /* do it twice to force the change */
2535 tact->set_active (!yn);
2536 tact->set_active (yn);
2539 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2540 yn = _follow_playhead;
2542 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2543 if (tact->get_active() != yn) {
2544 tact->set_active (yn);
2548 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2549 yn = _stationary_playhead;
2551 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2552 if (tact->get_active() != yn) {
2553 tact->set_active (yn);
2558 return LuaInstance::instance()->set_state(node);
2562 Editor::get_state ()
2564 XMLNode* node = new XMLNode (X_("Editor"));
2567 node->set_property ("id", id().to_s ());
2569 node->add_child_nocopy (Tabbable::get_state());
2571 node->set_property("edit-horizontal-pane-pos", edit_pane.get_divider ());
2572 node->set_property("notebook-shrunk", _notebook_shrunk);
2573 node->set_property("edit-vertical-pane-pos", editor_summary_pane.get_divider());
2575 maybe_add_mixer_strip_width (*node);
2577 node->set_property ("zoom-focus", zoom_focus);
2579 node->set_property ("zoom", samples_per_pixel);
2580 node->set_property ("snap-to", _snap_type);
2581 node->set_property ("snap-mode", _snap_mode);
2582 node->set_property ("internal-snap-to", internal_snap_type);
2583 node->set_property ("internal-snap-mode", internal_snap_mode);
2584 node->set_property ("pre-internal-snap-to", pre_internal_snap_type);
2585 node->set_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2586 node->set_property ("edit-point", _edit_point);
2587 node->set_property ("visible-track-count", _visible_track_count);
2589 node->set_property ("playhead", playhead_cursor->current_frame ());
2590 node->set_property ("left-frame", leftmost_frame);
2591 node->set_property ("y-origin", vertical_adjustment.get_value ());
2593 node->set_property ("show-measures", _show_measures);
2594 node->set_property ("maximised", _maximised);
2595 node->set_property ("follow-playhead", _follow_playhead);
2596 node->set_property ("stationary-playhead", _stationary_playhead);
2597 node->set_property ("region-list-sort-type", _regions->sort_type ());
2598 node->set_property ("mouse-mode", mouse_mode);
2599 node->set_property ("join-object-range", smart_mode_action->get_active ());
2601 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2603 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2604 node->set_property (X_("show-editor-mixer"), tact->get_active());
2607 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2609 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2610 node->set_property (X_("show-editor-list"), tact->get_active());
2613 node->set_property (X_("editor-list-page"), _the_notebook.get_current_page ());
2615 if (button_bindings) {
2616 XMLNode* bb = new XMLNode (X_("Buttons"));
2617 button_bindings->save (*bb);
2618 node->add_child_nocopy (*bb);
2621 node->set_property (X_("show-marker-lines"), _show_marker_lines);
2623 node->add_child_nocopy (selection->get_state ());
2624 node->add_child_nocopy (_regions->get_state ());
2626 node->set_property ("nudge-clock-value", nudge_clock->current_duration());
2628 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2629 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2630 node->add_child_nocopy (_locations->get_state ());
2635 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2636 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2638 * @return pair: TimeAxisView that y is over, layer index.
2640 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2641 * in stacked or expanded region display mode, otherwise 0.
2643 std::pair<TimeAxisView *, double>
2644 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2646 if (!trackview_relative_offset) {
2647 y -= _trackview_group->canvas_origin().y;
2651 return std::make_pair ( (TimeAxisView *) 0, 0);
2654 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2656 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2663 return std::make_pair ( (TimeAxisView *) 0, 0);
2666 /** Snap a position to the grid, if appropriate, taking into account current
2667 * grid settings and also the state of any snap modifier keys that may be pressed.
2668 * @param start Position to snap.
2669 * @param event Event to get current key modifier information from, or 0.
2672 Editor::snap_to_with_modifier (MusicFrame& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2674 if (!_session || !event) {
2678 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2679 if (_snap_mode == SnapOff) {
2680 snap_to_internal (start, direction, for_mark);
2682 start.set (start.frame, 0);
2685 if (_snap_mode != SnapOff) {
2686 snap_to_internal (start, direction, for_mark);
2687 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2688 /* SnapOff, but we pressed the snap_delta modifier */
2689 snap_to_internal (start, direction, for_mark);
2691 start.set (start.frame, 0);
2697 Editor::snap_to (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap)
2699 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2700 start.set (start.frame, 0);
2704 snap_to_internal (start, direction, for_mark, ensure_snap);
2708 Editor::timecode_snap_to_internal (MusicFrame& pos, RoundMode direction, bool /*for_mark*/)
2710 framepos_t start = pos.frame;
2711 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2712 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2714 switch (_snap_type) {
2715 case SnapToTimecodeFrame:
2716 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2717 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2718 /* start is already on a whole timecode frame, do nothing */
2719 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2720 start = (framepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2722 start = (framepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2726 case SnapToTimecodeSeconds:
2727 if (_session->config.get_timecode_offset_negative()) {
2728 start += _session->config.get_timecode_offset ();
2730 start -= _session->config.get_timecode_offset ();
2732 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2733 (start % one_timecode_second == 0)) {
2734 /* start is already on a whole second, do nothing */
2735 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2736 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2738 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2741 if (_session->config.get_timecode_offset_negative()) {
2742 start -= _session->config.get_timecode_offset ();
2744 start += _session->config.get_timecode_offset ();
2748 case SnapToTimecodeMinutes:
2749 if (_session->config.get_timecode_offset_negative()) {
2750 start += _session->config.get_timecode_offset ();
2752 start -= _session->config.get_timecode_offset ();
2754 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2755 (start % one_timecode_minute == 0)) {
2756 /* start is already on a whole minute, do nothing */
2757 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2758 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2760 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2762 if (_session->config.get_timecode_offset_negative()) {
2763 start -= _session->config.get_timecode_offset ();
2765 start += _session->config.get_timecode_offset ();
2769 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2770 abort(); /*NOTREACHED*/
2777 Editor::snap_to_internal (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap)
2779 const framepos_t one_second = _session->frame_rate();
2780 const framepos_t one_minute = _session->frame_rate() * 60;
2781 framepos_t presnap = start.frame;
2785 switch (_snap_type) {
2786 case SnapToTimecodeFrame:
2787 case SnapToTimecodeSeconds:
2788 case SnapToTimecodeMinutes:
2789 return timecode_snap_to_internal (start, direction, for_mark);
2792 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2793 start.frame % (one_second/75) == 0) {
2794 /* start is already on a whole CD frame, do nothing */
2795 } else if (((direction == 0) && (start.frame % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2796 start.frame = (framepos_t) ceil ((double) start.frame / (one_second / 75)) * (one_second / 75);
2798 start.frame = (framepos_t) floor ((double) start.frame / (one_second / 75)) * (one_second / 75);
2801 start.set (start.frame, 0);
2806 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2807 start.frame % one_second == 0) {
2808 /* start is already on a whole second, do nothing */
2809 } else if (((direction == 0) && (start.frame % one_second > one_second / 2)) || (direction > 0)) {
2810 start.frame = (framepos_t) ceil ((double) start.frame / one_second) * one_second;
2812 start.frame = (framepos_t) floor ((double) start.frame / one_second) * one_second;
2815 start.set (start.frame, 0);
2820 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2821 start.frame % one_minute == 0) {
2822 /* start is already on a whole minute, do nothing */
2823 } else if (((direction == 0) && (start.frame % one_minute > one_minute / 2)) || (direction > 0)) {
2824 start.frame = (framepos_t) ceil ((double) start.frame / one_minute) * one_minute;
2826 start.frame = (framepos_t) floor ((double) start.frame / one_minute) * one_minute;
2829 start.set (start.frame, 0);
2834 start = _session->tempo_map().round_to_bar (start.frame, direction);
2838 start = _session->tempo_map().round_to_beat (start.frame, direction);
2841 case SnapToBeatDiv128:
2842 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 128, direction);
2844 case SnapToBeatDiv64:
2845 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 64, direction);
2847 case SnapToBeatDiv32:
2848 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 32, direction);
2850 case SnapToBeatDiv28:
2851 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 28, direction);
2853 case SnapToBeatDiv24:
2854 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 24, direction);
2856 case SnapToBeatDiv20:
2857 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 20, direction);
2859 case SnapToBeatDiv16:
2860 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 16, direction);
2862 case SnapToBeatDiv14:
2863 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 14, direction);
2865 case SnapToBeatDiv12:
2866 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 12, direction);
2868 case SnapToBeatDiv10:
2869 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 10, direction);
2871 case SnapToBeatDiv8:
2872 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 8, direction);
2874 case SnapToBeatDiv7:
2875 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 7, direction);
2877 case SnapToBeatDiv6:
2878 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 6, direction);
2880 case SnapToBeatDiv5:
2881 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 5, direction);
2883 case SnapToBeatDiv4:
2884 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 4, direction);
2886 case SnapToBeatDiv3:
2887 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 3, direction);
2889 case SnapToBeatDiv2:
2890 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 2, direction);
2898 _session->locations()->marks_either_side (start.frame, before, after);
2900 if (before == max_framepos && after == max_framepos) {
2901 /* No marks to snap to, so just don't snap */
2903 } else if (before == max_framepos) {
2904 start.frame = after;
2905 } else if (after == max_framepos) {
2906 start.frame = before;
2907 } else if (before != max_framepos && after != max_framepos) {
2908 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2909 start.frame = after;
2910 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2911 start.frame = before;
2912 else if (direction == 0 ) {
2913 if ((start.frame - before) < (after - start.frame)) {
2914 start.frame = before;
2916 start.frame = after;
2921 start.set (start.frame, 0);
2925 case SnapToRegionStart:
2926 case SnapToRegionEnd:
2927 case SnapToRegionSync:
2928 case SnapToRegionBoundary:
2929 if (!region_boundary_cache.empty()) {
2931 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2932 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2934 if (direction > 0) {
2935 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame);
2937 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame);
2940 if (next != region_boundary_cache.begin ()) {
2945 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2946 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2948 if (start.frame > (p + n) / 2) {
2955 start.set (start.frame, 0);
2960 switch (_snap_mode) {
2970 if (presnap > start.frame) {
2971 if (presnap > (start.frame + pixel_to_sample(snap_threshold))) {
2972 start.set (presnap, 0);
2975 } else if (presnap < start.frame) {
2976 if (presnap < (start.frame - pixel_to_sample(snap_threshold))) {
2977 start.set (presnap, 0);
2982 /* handled at entry */
2989 Editor::setup_toolbar ()
2991 HBox* mode_box = manage(new HBox);
2992 mode_box->set_border_width (2);
2993 mode_box->set_spacing(2);
2995 HBox* mouse_mode_box = manage (new HBox);
2996 HBox* mouse_mode_hbox = manage (new HBox);
2997 VBox* mouse_mode_vbox = manage (new VBox);
2998 Alignment* mouse_mode_align = manage (new Alignment);
3000 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3001 mouse_mode_size_group->add_widget (smart_mode_button);
3002 mouse_mode_size_group->add_widget (mouse_move_button);
3003 mouse_mode_size_group->add_widget (mouse_cut_button);
3004 mouse_mode_size_group->add_widget (mouse_select_button);
3005 mouse_mode_size_group->add_widget (mouse_timefx_button);
3006 mouse_mode_size_group->add_widget (mouse_audition_button);
3007 mouse_mode_size_group->add_widget (mouse_draw_button);
3008 mouse_mode_size_group->add_widget (mouse_content_button);
3010 if (!Profile->get_mixbus()) {
3011 mouse_mode_size_group->add_widget (zoom_in_button);
3012 mouse_mode_size_group->add_widget (zoom_out_button);
3013 mouse_mode_size_group->add_widget (zoom_out_full_button);
3014 mouse_mode_size_group->add_widget (zoom_focus_selector);
3015 mouse_mode_size_group->add_widget (tav_shrink_button);
3016 mouse_mode_size_group->add_widget (tav_expand_button);
3018 mouse_mode_size_group->add_widget (zoom_preset_selector);
3019 mouse_mode_size_group->add_widget (visible_tracks_selector);
3022 mouse_mode_size_group->add_widget (snap_type_selector);
3023 mouse_mode_size_group->add_widget (snap_mode_selector);
3025 mouse_mode_size_group->add_widget (edit_point_selector);
3026 mouse_mode_size_group->add_widget (edit_mode_selector);
3028 mouse_mode_size_group->add_widget (*nudge_clock);
3029 mouse_mode_size_group->add_widget (nudge_forward_button);
3030 mouse_mode_size_group->add_widget (nudge_backward_button);
3032 mouse_mode_hbox->set_spacing (2);
3034 if (!ARDOUR::Profile->get_trx()) {
3035 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3038 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3039 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3041 if (!ARDOUR::Profile->get_mixbus()) {
3042 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3045 if (!ARDOUR::Profile->get_trx()) {
3046 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3047 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3048 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3049 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3052 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3054 mouse_mode_align->add (*mouse_mode_vbox);
3055 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3057 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3059 edit_mode_selector.set_name ("mouse mode button");
3061 if (!ARDOUR::Profile->get_trx()) {
3062 mode_box->pack_start (edit_mode_selector, false, false);
3065 mode_box->pack_start (*mouse_mode_box, false, false);
3069 _zoom_box.set_spacing (2);
3070 _zoom_box.set_border_width (2);
3074 zoom_preset_selector.set_name ("zoom button");
3075 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
3077 zoom_in_button.set_name ("zoom button");
3078 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3079 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3080 zoom_in_button.set_related_action (act);
3082 zoom_out_button.set_name ("zoom button");
3083 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3084 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3085 zoom_out_button.set_related_action (act);
3087 zoom_out_full_button.set_name ("zoom button");
3088 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3089 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3090 zoom_out_full_button.set_related_action (act);
3092 zoom_focus_selector.set_name ("zoom button");
3094 if (ARDOUR::Profile->get_mixbus()) {
3095 _zoom_box.pack_start (zoom_preset_selector, false, false);
3096 } else if (ARDOUR::Profile->get_trx()) {
3097 mode_box->pack_start (zoom_out_button, false, false);
3098 mode_box->pack_start (zoom_in_button, false, false);
3100 _zoom_box.pack_start (zoom_out_button, false, false);
3101 _zoom_box.pack_start (zoom_in_button, false, false);
3102 _zoom_box.pack_start (zoom_out_full_button, false, false);
3103 _zoom_box.pack_start (zoom_focus_selector, false, false);
3106 /* Track zoom buttons */
3107 _track_box.set_spacing (2);
3108 _track_box.set_border_width (2);
3110 visible_tracks_selector.set_name ("zoom button");
3111 if (Profile->get_mixbus()) {
3112 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3114 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3117 tav_expand_button.set_name ("zoom button");
3118 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3119 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3120 tav_expand_button.set_related_action (act);
3122 tav_shrink_button.set_name ("zoom button");
3123 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3124 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3125 tav_shrink_button.set_related_action (act);
3127 if (ARDOUR::Profile->get_mixbus()) {
3128 _track_box.pack_start (visible_tracks_selector);
3129 } else if (ARDOUR::Profile->get_trx()) {
3130 _track_box.pack_start (tav_shrink_button);
3131 _track_box.pack_start (tav_expand_button);
3133 _track_box.pack_start (visible_tracks_selector);
3134 _track_box.pack_start (tav_shrink_button);
3135 _track_box.pack_start (tav_expand_button);
3138 snap_box.set_spacing (2);
3139 snap_box.set_border_width (2);
3141 snap_type_selector.set_name ("mouse mode button");
3143 snap_mode_selector.set_name ("mouse mode button");
3145 edit_point_selector.set_name ("mouse mode button");
3147 snap_box.pack_start (snap_mode_selector, false, false);
3148 snap_box.pack_start (snap_type_selector, false, false);
3151 HBox *ep_box = manage (new HBox);
3152 ep_box->set_spacing (2);
3153 ep_box->set_border_width (2);
3155 ep_box->pack_start (edit_point_selector, false, false);
3159 HBox *nudge_box = manage (new HBox);
3160 nudge_box->set_spacing (2);
3161 nudge_box->set_border_width (2);
3163 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3164 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3166 nudge_box->pack_start (nudge_backward_button, false, false);
3167 nudge_box->pack_start (nudge_forward_button, false, false);
3168 nudge_box->pack_start (*nudge_clock, false, false);
3171 /* Pack everything in... */
3173 toolbar_hbox.set_spacing (2);
3174 toolbar_hbox.set_border_width (2);
3176 toolbar_hbox.pack_start (*mode_box, false, false);
3178 if (!ARDOUR::Profile->get_trx()) {
3180 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3182 toolbar_hbox.pack_start (_zoom_box, false, false);
3184 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3186 toolbar_hbox.pack_start (_track_box, false, false);
3188 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3190 toolbar_hbox.pack_start (snap_box, false, false);
3192 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3194 toolbar_hbox.pack_start (*ep_box, false, false);
3196 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3198 toolbar_hbox.pack_start (*nudge_box, false, false);
3201 toolbar_hbox.show_all ();
3205 Editor::build_edit_point_menu ()
3207 using namespace Menu_Helpers;
3209 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3210 if(!Profile->get_mixbus())
3211 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3212 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3214 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3218 Editor::build_edit_mode_menu ()
3220 using namespace Menu_Helpers;
3222 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3223 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3224 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3225 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3227 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3231 Editor::build_snap_mode_menu ()
3233 using namespace Menu_Helpers;
3235 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3236 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3237 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3239 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3243 Editor::build_snap_type_menu ()
3245 using namespace Menu_Helpers;
3247 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3248 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3249 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3250 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3251 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3252 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3253 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3254 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3255 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3256 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3257 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3258 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3259 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3260 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3261 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3262 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3263 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3264 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3265 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3266 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3267 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3268 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3269 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3270 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3271 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3272 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3273 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3274 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3275 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3276 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3278 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3283 Editor::setup_tooltips ()
3285 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3286 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3287 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3288 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3289 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3290 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3291 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3292 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3293 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3294 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3295 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3296 set_tooltip (zoom_in_button, _("Zoom In"));
3297 set_tooltip (zoom_out_button, _("Zoom Out"));
3298 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3299 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3300 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3301 set_tooltip (tav_expand_button, _("Expand Tracks"));
3302 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3303 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3304 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3305 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3306 set_tooltip (edit_point_selector, _("Edit Point"));
3307 set_tooltip (edit_mode_selector, _("Edit Mode"));
3308 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3312 Editor::convert_drop_to_paths (
3313 vector<string>& paths,
3314 const RefPtr<Gdk::DragContext>& /*context*/,
3317 const SelectionData& data,
3321 if (_session == 0) {
3325 vector<string> uris = data.get_uris();
3329 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3330 are actually URI lists. So do it by hand.
3333 if (data.get_target() != "text/plain") {
3337 /* Parse the "uri-list" format that Nautilus provides,
3338 where each pathname is delimited by \r\n.
3340 THERE MAY BE NO NULL TERMINATING CHAR!!!
3343 string txt = data.get_text();
3347 p = (char *) malloc (txt.length() + 1);
3348 txt.copy (p, txt.length(), 0);
3349 p[txt.length()] = '\0';
3355 while (g_ascii_isspace (*p))
3359 while (*q && (*q != '\n') && (*q != '\r')) {
3366 while (q > p && g_ascii_isspace (*q))
3371 uris.push_back (string (p, q - p + 1));
3375 p = strchr (p, '\n');
3387 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3388 if ((*i).substr (0,7) == "file://") {
3389 paths.push_back (Glib::filename_from_uri (*i));
3397 Editor::new_tempo_section ()
3402 Editor::map_transport_state ()
3404 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3406 if (_session && _session->transport_stopped()) {
3407 have_pending_keyboard_selection = false;
3410 update_loop_range_view ();
3414 Editor::transport_looped ()
3416 /* reset Playhead position interpolation.
3417 * see Editor::super_rapid_screen_update
3419 _last_update_time = 0;
3425 Editor::begin_selection_op_history ()
3427 selection_op_cmd_depth = 0;
3428 selection_op_history_it = 0;
3430 while(!selection_op_history.empty()) {
3431 delete selection_op_history.front();
3432 selection_op_history.pop_front();
3435 selection_undo_action->set_sensitive (false);
3436 selection_redo_action->set_sensitive (false);
3437 selection_op_history.push_front (&_selection_memento->get_state ());
3441 Editor::begin_reversible_selection_op (string name)
3444 //cerr << name << endl;
3445 /* begin/commit pairs can be nested */
3446 selection_op_cmd_depth++;
3451 Editor::commit_reversible_selection_op ()
3454 if (selection_op_cmd_depth == 1) {
3456 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3458 The user has undone some selection ops and then made a new one,
3459 making anything earlier in the list invalid.
3462 list<XMLNode *>::iterator it = selection_op_history.begin();
3463 list<XMLNode *>::iterator e_it = it;
3464 advance (e_it, selection_op_history_it);
3466 for ( ; it != e_it; ++it) {
3469 selection_op_history.erase (selection_op_history.begin(), e_it);
3472 selection_op_history.push_front (&_selection_memento->get_state ());
3473 selection_op_history_it = 0;
3475 selection_undo_action->set_sensitive (true);
3476 selection_redo_action->set_sensitive (false);
3479 if (selection_op_cmd_depth > 0) {
3480 selection_op_cmd_depth--;
3486 Editor::undo_selection_op ()
3489 selection_op_history_it++;
3491 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3492 if (n == selection_op_history_it) {
3493 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3494 selection_redo_action->set_sensitive (true);
3498 /* is there an earlier entry? */
3499 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3500 selection_undo_action->set_sensitive (false);
3506 Editor::redo_selection_op ()
3509 if (selection_op_history_it > 0) {
3510 selection_op_history_it--;
3513 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3514 if (n == selection_op_history_it) {
3515 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3516 selection_undo_action->set_sensitive (true);
3521 if (selection_op_history_it == 0) {
3522 selection_redo_action->set_sensitive (false);
3528 Editor::begin_reversible_command (string name)
3531 before.push_back (&_selection_memento->get_state ());
3532 _session->begin_reversible_command (name);
3537 Editor::begin_reversible_command (GQuark q)
3540 before.push_back (&_selection_memento->get_state ());
3541 _session->begin_reversible_command (q);
3546 Editor::abort_reversible_command ()
3549 while(!before.empty()) {
3550 delete before.front();
3553 _session->abort_reversible_command ();
3558 Editor::commit_reversible_command ()
3561 if (before.size() == 1) {
3562 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3563 redo_action->set_sensitive(false);
3564 undo_action->set_sensitive(true);
3565 begin_selection_op_history ();
3568 if (before.empty()) {
3569 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3574 _session->commit_reversible_command ();
3579 Editor::history_changed ()
3583 if (undo_action && _session) {
3584 if (_session->undo_depth() == 0) {
3585 label = S_("Command|Undo");
3587 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3589 undo_action->property_label() = label;
3592 if (redo_action && _session) {
3593 if (_session->redo_depth() == 0) {
3595 redo_action->set_sensitive (false);
3597 label = string_compose(_("Redo (%1)"), _session->next_redo());
3598 redo_action->set_sensitive (true);
3600 redo_action->property_label() = label;
3605 Editor::duplicate_range (bool with_dialog)
3609 RegionSelection rs = get_regions_from_selection_and_entered ();
3611 if ( selection->time.length() == 0 && rs.empty()) {
3617 ArdourDialog win (_("Duplicate"));
3618 Label label (_("Number of duplications:"));
3619 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3620 SpinButton spinner (adjustment, 0.0, 1);
3623 win.get_vbox()->set_spacing (12);
3624 win.get_vbox()->pack_start (hbox);
3625 hbox.set_border_width (6);
3626 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3628 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3629 place, visually. so do this by hand.
3632 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3633 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3634 spinner.grab_focus();
3640 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3641 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3642 win.set_default_response (RESPONSE_ACCEPT);
3644 spinner.grab_focus ();
3646 switch (win.run ()) {
3647 case RESPONSE_ACCEPT:
3653 times = adjustment.get_value();
3656 if ((current_mouse_mode() == Editing::MouseRange)) {
3657 if (selection->time.length()) {
3658 duplicate_selection (times);
3660 } else if (get_smart_mode()) {
3661 if (selection->time.length()) {
3662 duplicate_selection (times);
3664 duplicate_some_regions (rs, times);
3666 duplicate_some_regions (rs, times);
3671 Editor::set_edit_mode (EditMode m)
3673 Config->set_edit_mode (m);
3677 Editor::cycle_edit_mode ()
3679 switch (Config->get_edit_mode()) {
3681 Config->set_edit_mode (Ripple);
3685 Config->set_edit_mode (Lock);
3688 Config->set_edit_mode (Slide);
3694 Editor::edit_mode_selection_done ( EditMode m )
3696 Config->set_edit_mode ( m );
3700 Editor::snap_type_selection_done (SnapType snaptype)
3702 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3704 ract->set_active ();
3709 Editor::snap_mode_selection_done (SnapMode mode)
3711 RefPtr<RadioAction> ract = snap_mode_action (mode);
3714 ract->set_active (true);
3719 Editor::cycle_edit_point (bool with_marker)
3721 if(Profile->get_mixbus())
3722 with_marker = false;
3724 switch (_edit_point) {
3726 set_edit_point_preference (EditAtPlayhead);
3728 case EditAtPlayhead:
3730 set_edit_point_preference (EditAtSelectedMarker);
3732 set_edit_point_preference (EditAtMouse);
3735 case EditAtSelectedMarker:
3736 set_edit_point_preference (EditAtMouse);
3742 Editor::edit_point_selection_done (EditPoint ep)
3744 set_edit_point_preference ( ep );
3748 Editor::build_zoom_focus_menu ()
3750 using namespace Menu_Helpers;
3752 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3753 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3754 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3755 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3756 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3757 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3759 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3763 Editor::zoom_focus_selection_done ( ZoomFocus f )
3765 RefPtr<RadioAction> ract = zoom_focus_action (f);
3767 ract->set_active ();
3772 Editor::build_track_count_menu ()
3774 using namespace Menu_Helpers;
3776 if (!Profile->get_mixbus()) {
3777 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3778 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3779 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3780 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3781 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3782 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3783 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3784 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3785 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3786 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3787 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3788 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3789 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3791 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3792 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3793 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3794 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3795 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3796 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3797 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3798 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3799 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3800 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3802 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3803 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3804 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3805 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3806 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3807 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3808 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3809 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3810 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3811 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3812 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3817 Editor::set_zoom_preset (int64_t ms)
3820 temporal_zoom_session();
3824 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3825 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3829 Editor::set_visible_track_count (int32_t n)
3831 _visible_track_count = n;
3833 /* if the canvas hasn't really been allocated any size yet, just
3834 record the desired number of visible tracks and return. when canvas
3835 allocation happens, we will get called again and then we can do the
3839 if (_visible_canvas_height <= 1) {
3845 DisplaySuspender ds;
3847 if (_visible_track_count > 0) {
3848 h = trackviews_height() / _visible_track_count;
3849 std::ostringstream s;
3850 s << _visible_track_count;
3852 } else if (_visible_track_count == 0) {
3854 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3855 if ((*i)->marked_for_display()) {
3859 h = trackviews_height() / n;
3862 /* negative value means that the visible track count has
3863 been overridden by explicit track height changes.
3865 visible_tracks_selector.set_text (X_("*"));
3869 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3870 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3873 if (str != visible_tracks_selector.get_text()) {
3874 visible_tracks_selector.set_text (str);
3879 Editor::override_visible_track_count ()
3881 _visible_track_count = -1;
3882 visible_tracks_selector.set_text ( _("*") );
3886 Editor::edit_controls_button_release (GdkEventButton* ev)
3888 if (Keyboard::is_context_menu_event (ev)) {
3889 ARDOUR_UI::instance()->add_route ();
3890 } else if (ev->button == 1) {
3891 selection->clear_tracks ();
3898 Editor::mouse_select_button_release (GdkEventButton* ev)
3900 /* this handles just right-clicks */
3902 if (ev->button != 3) {
3910 Editor::set_zoom_focus (ZoomFocus f)
3912 string str = zoom_focus_strings[(int)f];
3914 if (str != zoom_focus_selector.get_text()) {
3915 zoom_focus_selector.set_text (str);
3918 if (zoom_focus != f) {
3925 Editor::cycle_zoom_focus ()
3927 switch (zoom_focus) {
3929 set_zoom_focus (ZoomFocusRight);
3931 case ZoomFocusRight:
3932 set_zoom_focus (ZoomFocusCenter);
3934 case ZoomFocusCenter:
3935 set_zoom_focus (ZoomFocusPlayhead);
3937 case ZoomFocusPlayhead:
3938 set_zoom_focus (ZoomFocusMouse);
3940 case ZoomFocusMouse:
3941 set_zoom_focus (ZoomFocusEdit);
3944 set_zoom_focus (ZoomFocusLeft);
3950 Editor::set_show_measures (bool yn)
3952 if (_show_measures != yn) {
3955 if ((_show_measures = yn) == true) {
3957 tempo_lines->show();
3960 std::vector<TempoMap::BBTPoint> grid;
3961 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3962 draw_measures (grid);
3970 Editor::toggle_follow_playhead ()
3972 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3974 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3975 set_follow_playhead (tact->get_active());
3979 /** @param yn true to follow playhead, otherwise false.
3980 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3983 Editor::set_follow_playhead (bool yn, bool catch_up)
3985 if (_follow_playhead != yn) {
3986 if ((_follow_playhead = yn) == true && catch_up) {
3988 reset_x_origin_to_follow_playhead ();
3995 Editor::toggle_stationary_playhead ()
3997 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3999 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4000 set_stationary_playhead (tact->get_active());
4005 Editor::set_stationary_playhead (bool yn)
4007 if (_stationary_playhead != yn) {
4008 if ((_stationary_playhead = yn) == true) {
4010 // FIXME need a 3.0 equivalent of this 2.X call
4011 // update_current_screen ();
4018 Editor::playlist_selector () const
4020 return *_playlist_selector;
4024 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4026 if (paste_count == 0) {
4027 /* don't bother calculating an offset that will be zero anyway */
4031 /* calculate basic unsnapped multi-paste offset */
4032 framecnt_t offset = paste_count * duration;
4034 /* snap offset so pos + offset is aligned to the grid */
4035 MusicFrame offset_pos (pos + offset, 0);
4036 snap_to(offset_pos, RoundUpMaybe);
4037 offset = offset_pos.frame - pos;
4043 Editor::get_grid_beat_divisions(framepos_t position)
4045 switch (_snap_type) {
4046 case SnapToBeatDiv128: return 128;
4047 case SnapToBeatDiv64: return 64;
4048 case SnapToBeatDiv32: return 32;
4049 case SnapToBeatDiv28: return 28;
4050 case SnapToBeatDiv24: return 24;
4051 case SnapToBeatDiv20: return 20;
4052 case SnapToBeatDiv16: return 16;
4053 case SnapToBeatDiv14: return 14;
4054 case SnapToBeatDiv12: return 12;
4055 case SnapToBeatDiv10: return 10;
4056 case SnapToBeatDiv8: return 8;
4057 case SnapToBeatDiv7: return 7;
4058 case SnapToBeatDiv6: return 6;
4059 case SnapToBeatDiv5: return 5;
4060 case SnapToBeatDiv4: return 4;
4061 case SnapToBeatDiv3: return 3;
4062 case SnapToBeatDiv2: return 2;
4068 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4069 if the grid is non-musical, returns 0.
4070 if the grid is snapped to bars, returns -1.
4071 @param event_state the current keyboard modifier mask.
4074 Editor::get_grid_music_divisions (uint32_t event_state)
4076 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4080 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4084 switch (_snap_type) {
4085 case SnapToBeatDiv128: return 128;
4086 case SnapToBeatDiv64: return 64;
4087 case SnapToBeatDiv32: return 32;
4088 case SnapToBeatDiv28: return 28;
4089 case SnapToBeatDiv24: return 24;
4090 case SnapToBeatDiv20: return 20;
4091 case SnapToBeatDiv16: return 16;
4092 case SnapToBeatDiv14: return 14;
4093 case SnapToBeatDiv12: return 12;
4094 case SnapToBeatDiv10: return 10;
4095 case SnapToBeatDiv8: return 8;
4096 case SnapToBeatDiv7: return 7;
4097 case SnapToBeatDiv6: return 6;
4098 case SnapToBeatDiv5: return 5;
4099 case SnapToBeatDiv4: return 4;
4100 case SnapToBeatDiv3: return 3;
4101 case SnapToBeatDiv2: return 2;
4102 case SnapToBeat: return 1;
4103 case SnapToBar : return -1;
4110 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4114 const unsigned divisions = get_grid_beat_divisions(position);
4116 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4119 switch (_snap_type) {
4121 return Evoral::Beats(4.0 / _session->tempo_map().meter_at_frame (position).note_divisor());
4124 const Meter& m = _session->tempo_map().meter_at_frame (position);
4125 return Evoral::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4133 return Evoral::Beats();
4137 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4141 ret = nudge_clock->current_duration (pos);
4142 next = ret + 1; /* XXXX fix me */
4148 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4150 ArdourDialog dialog (_("Playlist Deletion"));
4151 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4152 "If it is kept, its audio files will not be cleaned.\n"
4153 "If it is deleted, audio files used by it alone will be cleaned."),
4156 dialog.set_position (WIN_POS_CENTER);
4157 dialog.get_vbox()->pack_start (label);
4161 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4162 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4163 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4164 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4165 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4167 // by default gtk uses the left most button
4168 keep->grab_focus ();
4170 switch (dialog.run ()) {
4172 /* keep this and all remaining ones */
4177 /* delete this and all others */
4181 case RESPONSE_ACCEPT:
4182 /* delete the playlist */
4186 case RESPONSE_REJECT:
4187 /* keep the playlist */
4199 Editor::audio_region_selection_covers (framepos_t where)
4201 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4202 if ((*a)->region()->covers (where)) {
4211 Editor::prepare_for_cleanup ()
4213 cut_buffer->clear_regions ();
4214 cut_buffer->clear_playlists ();
4216 selection->clear_regions ();
4217 selection->clear_playlists ();
4219 _regions->suspend_redisplay ();
4223 Editor::finish_cleanup ()
4225 _regions->resume_redisplay ();
4229 Editor::transport_loop_location()
4232 return _session->locations()->auto_loop_location();
4239 Editor::transport_punch_location()
4242 return _session->locations()->auto_punch_location();
4249 Editor::control_layout_scroll (GdkEventScroll* ev)
4251 /* Just forward to the normal canvas scroll method. The coordinate
4252 systems are different but since the canvas is always larger than the
4253 track headers, and aligned with the trackview area, this will work.
4255 In the not too distant future this layout is going away anyway and
4256 headers will be on the canvas.
4258 return canvas_scroll_event (ev, false);
4262 Editor::session_state_saved (string)
4265 _snapshots->redisplay ();
4269 Editor::maximise_editing_space ()
4275 Gtk::Window* toplevel = current_toplevel();
4278 toplevel->fullscreen ();
4284 Editor::restore_editing_space ()
4290 Gtk::Window* toplevel = current_toplevel();
4293 toplevel->unfullscreen();
4299 * Make new playlists for a given track and also any others that belong
4300 * to the same active route group with the `select' property.
4305 Editor::new_playlists (TimeAxisView* v)
4307 begin_reversible_command (_("new playlists"));
4308 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4309 _session->playlists->get (playlists);
4310 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4311 commit_reversible_command ();
4315 * Use a copy of the current playlist for a given track and also any others that belong
4316 * to the same active route group with the `select' property.
4321 Editor::copy_playlists (TimeAxisView* v)
4323 begin_reversible_command (_("copy playlists"));
4324 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4325 _session->playlists->get (playlists);
4326 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4327 commit_reversible_command ();
4330 /** Clear 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::clear_playlists (TimeAxisView* v)
4338 begin_reversible_command (_("clear playlists"));
4339 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4340 _session->playlists->get (playlists);
4341 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4342 commit_reversible_command ();
4346 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4348 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4352 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4354 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4358 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4360 atv.clear_playlist ();
4364 Editor::get_y_origin () const
4366 return vertical_adjustment.get_value ();
4369 /** Queue up a change to the viewport x origin.
4370 * @param frame New x origin.
4373 Editor::reset_x_origin (framepos_t frame)
4375 pending_visual_change.add (VisualChange::TimeOrigin);
4376 pending_visual_change.time_origin = frame;
4377 ensure_visual_change_idle_handler ();
4381 Editor::reset_y_origin (double y)
4383 pending_visual_change.add (VisualChange::YOrigin);
4384 pending_visual_change.y_origin = y;
4385 ensure_visual_change_idle_handler ();
4389 Editor::reset_zoom (framecnt_t spp)
4391 if (spp == samples_per_pixel) {
4395 pending_visual_change.add (VisualChange::ZoomLevel);
4396 pending_visual_change.samples_per_pixel = spp;
4397 ensure_visual_change_idle_handler ();
4401 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4403 reset_x_origin (frame);
4406 if (!no_save_visual) {
4407 undo_visual_stack.push_back (current_visual_state(false));
4411 Editor::VisualState::VisualState (bool with_tracks)
4412 : gui_state (with_tracks ? new GUIObjectState : 0)
4416 Editor::VisualState::~VisualState ()
4421 Editor::VisualState*
4422 Editor::current_visual_state (bool with_tracks)
4424 VisualState* vs = new VisualState (with_tracks);
4425 vs->y_position = vertical_adjustment.get_value();
4426 vs->samples_per_pixel = samples_per_pixel;
4427 vs->leftmost_frame = leftmost_frame;
4428 vs->zoom_focus = zoom_focus;
4431 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4438 Editor::undo_visual_state ()
4440 if (undo_visual_stack.empty()) {
4444 VisualState* vs = undo_visual_stack.back();
4445 undo_visual_stack.pop_back();
4448 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4451 use_visual_state (*vs);
4456 Editor::redo_visual_state ()
4458 if (redo_visual_stack.empty()) {
4462 VisualState* vs = redo_visual_stack.back();
4463 redo_visual_stack.pop_back();
4465 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4466 // why do we check here?
4467 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4470 use_visual_state (*vs);
4475 Editor::swap_visual_state ()
4477 if (undo_visual_stack.empty()) {
4478 redo_visual_state ();
4480 undo_visual_state ();
4485 Editor::use_visual_state (VisualState& vs)
4487 PBD::Unwinder<bool> nsv (no_save_visual, true);
4488 DisplaySuspender ds;
4490 vertical_adjustment.set_value (vs.y_position);
4492 set_zoom_focus (vs.zoom_focus);
4493 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4496 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4498 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4499 (*i)->clear_property_cache();
4500 (*i)->reset_visual_state ();
4504 _routes->update_visibility ();
4507 /** This is the core function that controls the zoom level of the canvas. It is called
4508 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4509 * @param spp new number of samples per pixel
4512 Editor::set_samples_per_pixel (framecnt_t spp)
4518 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4519 const framecnt_t lots_of_pixels = 4000;
4521 /* if the zoom level is greater than what you'd get trying to display 3
4522 * days of audio on a really big screen, then it's too big.
4525 if (spp * lots_of_pixels > three_days) {
4529 samples_per_pixel = spp;
4532 tempo_lines->tempo_map_changed();
4535 bool const showing_time_selection = selection->time.length() > 0;
4537 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4538 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4539 (*i)->reshow_selection (selection->time);
4543 ZoomChanged (); /* EMIT_SIGNAL */
4545 ArdourCanvas::GtkCanvasViewport* c;
4547 c = get_track_canvas();
4549 c->canvas()->zoomed ();
4552 if (playhead_cursor) {
4553 playhead_cursor->set_position (playhead_cursor->current_frame ());
4556 refresh_location_display();
4557 _summary->set_overlays_dirty ();
4559 update_marker_labels ();
4565 Editor::playhead_cursor_sample () const
4567 return playhead_cursor->current_frame();
4571 Editor::queue_visual_videotimeline_update ()
4574 * pending_visual_change.add (VisualChange::VideoTimeline);
4575 * or maybe even more specific: which videotimeline-image
4576 * currently it calls update_video_timeline() to update
4577 * _all outdated_ images on the video-timeline.
4578 * see 'exposeimg()' in video_image_frame.cc
4580 ensure_visual_change_idle_handler ();
4584 Editor::ensure_visual_change_idle_handler ()
4586 if (pending_visual_change.idle_handler_id < 0) {
4587 // see comment in add_to_idle_resize above.
4588 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4589 pending_visual_change.being_handled = false;
4594 Editor::_idle_visual_changer (void* arg)
4596 return static_cast<Editor*>(arg)->idle_visual_changer ();
4600 Editor::idle_visual_changer ()
4602 /* set_horizontal_position() below (and maybe other calls) call
4603 gtk_main_iteration(), so it's possible that a signal will be handled
4604 half-way through this method. If this signal wants an
4605 idle_visual_changer we must schedule another one after this one, so
4606 mark the idle_handler_id as -1 here to allow that. Also make a note
4607 that we are doing the visual change, so that changes in response to
4608 super-rapid-screen-update can be dropped if we are still processing
4612 pending_visual_change.idle_handler_id = -1;
4613 pending_visual_change.being_handled = true;
4615 VisualChange vc = pending_visual_change;
4617 pending_visual_change.pending = (VisualChange::Type) 0;
4619 visual_changer (vc);
4621 pending_visual_change.being_handled = false;
4623 return 0; /* this is always a one-shot call */
4627 Editor::visual_changer (const VisualChange& vc)
4629 double const last_time_origin = horizontal_position ();
4631 if (vc.pending & VisualChange::ZoomLevel) {
4632 set_samples_per_pixel (vc.samples_per_pixel);
4634 compute_fixed_ruler_scale ();
4636 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4637 update_tempo_based_rulers ();
4639 update_video_timeline();
4642 if (vc.pending & VisualChange::TimeOrigin) {
4643 set_horizontal_position (sample_to_pixel_unrounded (vc.time_origin));
4646 if (vc.pending & VisualChange::YOrigin) {
4647 vertical_adjustment.set_value (vc.y_origin);
4650 if (last_time_origin == horizontal_position ()) {
4651 /* changed signal not emitted */
4652 update_fixed_rulers ();
4653 redisplay_tempo (true);
4656 if (!(vc.pending & VisualChange::ZoomLevel)) {
4657 update_video_timeline();
4660 _summary->set_overlays_dirty ();
4663 struct EditorOrderTimeAxisSorter {
4664 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4665 return a->order () < b->order ();
4670 Editor::sort_track_selection (TrackViewList& sel)
4672 EditorOrderTimeAxisSorter cmp;
4677 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4680 framepos_t where = 0;
4681 EditPoint ep = _edit_point;
4683 if (Profile->get_mixbus()) {
4684 if (ep == EditAtSelectedMarker) {
4685 ep = EditAtPlayhead;
4689 if (from_outside_canvas && (ep == EditAtMouse)) {
4690 ep = EditAtPlayhead;
4691 } else if (from_context_menu && (ep == EditAtMouse)) {
4692 return canvas_event_sample (&context_click_event, 0, 0);
4695 if (entered_marker) {
4696 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4697 return entered_marker->position();
4700 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4701 ep = EditAtSelectedMarker;
4704 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4705 ep = EditAtPlayhead;
4708 MusicFrame snap_mf (0, 0);
4711 case EditAtPlayhead:
4712 if (_dragging_playhead && _control_scroll_target) {
4713 where = *_control_scroll_target;
4715 where = _session->audible_frame();
4717 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4720 case EditAtSelectedMarker:
4721 if (!selection->markers.empty()) {
4723 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4726 where = loc->start();
4730 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4738 if (!mouse_frame (where, ignored)) {
4739 /* XXX not right but what can we do ? */
4742 snap_mf.frame = where;
4744 where = snap_mf.frame;
4745 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4753 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4755 if (!_session) return;
4757 begin_reversible_command (cmd);
4761 if ((tll = transport_loop_location()) == 0) {
4762 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4763 XMLNode &before = _session->locations()->get_state();
4764 _session->locations()->add (loc, true);
4765 _session->set_auto_loop_location (loc);
4766 XMLNode &after = _session->locations()->get_state();
4767 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4769 XMLNode &before = tll->get_state();
4770 tll->set_hidden (false, this);
4771 tll->set (start, end);
4772 XMLNode &after = tll->get_state();
4773 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4776 commit_reversible_command ();
4780 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4782 if (!_session) return;
4784 begin_reversible_command (cmd);
4788 if ((tpl = transport_punch_location()) == 0) {
4789 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4790 XMLNode &before = _session->locations()->get_state();
4791 _session->locations()->add (loc, true);
4792 _session->set_auto_punch_location (loc);
4793 XMLNode &after = _session->locations()->get_state();
4794 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4796 XMLNode &before = tpl->get_state();
4797 tpl->set_hidden (false, this);
4798 tpl->set (start, end);
4799 XMLNode &after = tpl->get_state();
4800 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4803 commit_reversible_command ();
4806 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4807 * @param rs List to which found regions are added.
4808 * @param where Time to look at.
4809 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4812 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4814 const TrackViewList* tracks;
4817 tracks = &track_views;
4822 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4824 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4827 boost::shared_ptr<Track> tr;
4828 boost::shared_ptr<Playlist> pl;
4830 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4832 boost::shared_ptr<RegionList> regions = pl->regions_at (
4833 (framepos_t) floor ( (double) where * tr->speed()));
4835 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4836 RegionView* rv = rtv->view()->find_view (*i);
4847 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4849 const TrackViewList* tracks;
4852 tracks = &track_views;
4857 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4858 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4860 boost::shared_ptr<Track> tr;
4861 boost::shared_ptr<Playlist> pl;
4863 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4865 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4866 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4868 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4870 RegionView* rv = rtv->view()->find_view (*i);
4881 /** Get regions using the following method:
4883 * Make a region list using:
4884 * (a) any selected regions
4885 * (b) the intersection of any selected tracks and the edit point(*)
4886 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4888 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4890 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4894 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4896 RegionSelection regions;
4898 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4899 regions.add (entered_regionview);
4901 regions = selection->regions;
4904 if ( regions.empty() ) {
4905 TrackViewList tracks = selection->tracks;
4907 if (!tracks.empty()) {
4908 /* no region selected or entered, but some selected tracks:
4909 * act on all regions on the selected tracks at the edit point
4911 framepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
4912 get_regions_at(regions, where, tracks);
4919 /** Get regions using the following method:
4921 * Make a region list using:
4922 * (a) any selected regions
4923 * (b) the intersection of any selected tracks and the edit point(*)
4924 * (c) if neither exists, then whatever region is under the mouse
4926 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4928 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4931 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4933 RegionSelection regions;
4935 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4936 regions.add (entered_regionview);
4938 regions = selection->regions;
4941 if ( regions.empty() ) {
4942 TrackViewList tracks = selection->tracks;
4944 if (!tracks.empty()) {
4945 /* no region selected or entered, but some selected tracks:
4946 * act on all regions on the selected tracks at the edit point
4948 get_regions_at(regions, pos, tracks);
4955 /** Start with regions that are selected, or the entered regionview if none are selected.
4956 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4957 * of the regions that we started with.
4961 Editor::get_regions_from_selection_and_entered () const
4963 RegionSelection regions = selection->regions;
4965 if (regions.empty() && entered_regionview) {
4966 regions.add (entered_regionview);
4973 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4975 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4976 RouteTimeAxisView* rtav;
4978 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4979 boost::shared_ptr<Playlist> pl;
4980 std::vector<boost::shared_ptr<Region> > results;
4981 boost::shared_ptr<Track> tr;
4983 if ((tr = rtav->track()) == 0) {
4988 if ((pl = (tr->playlist())) != 0) {
4989 boost::shared_ptr<Region> r = pl->region_by_id (id);
4991 RegionView* rv = rtav->view()->find_view (r);
4993 regions.push_back (rv);
5002 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
5005 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5006 MidiTimeAxisView* mtav;
5008 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5010 mtav->get_per_region_note_selection (selection);
5017 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5019 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5021 RouteTimeAxisView* tatv;
5023 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5025 boost::shared_ptr<Playlist> pl;
5026 vector<boost::shared_ptr<Region> > results;
5028 boost::shared_ptr<Track> tr;
5030 if ((tr = tatv->track()) == 0) {
5035 if ((pl = (tr->playlist())) != 0) {
5036 if (src_comparison) {
5037 pl->get_source_equivalent_regions (region, results);
5039 pl->get_region_list_equivalent_regions (region, results);
5043 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5044 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5045 regions.push_back (marv);
5054 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
5056 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5057 RouteTimeAxisView* tatv;
5058 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5059 if (!tatv->track()) {
5062 RegionView* marv = tatv->view()->find_view (region);
5072 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5074 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5075 RouteTimeAxisView* rtav;
5076 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5077 if (rtav->route() == route) {
5086 Editor::show_rhythm_ferret ()
5088 if (rhythm_ferret == 0) {
5089 rhythm_ferret = new RhythmFerret(*this);
5092 rhythm_ferret->set_session (_session);
5093 rhythm_ferret->show ();
5094 rhythm_ferret->present ();
5098 Editor::first_idle ()
5100 MessageDialog* dialog = 0;
5102 if (track_views.size() > 1) {
5103 Timers::TimerSuspender t;
5104 dialog = new MessageDialog (
5105 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5109 ARDOUR_UI::instance()->flush_pending (60);
5112 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5116 /* now that all regionviews should exist, setup region selection */
5120 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5121 /* this is cumulative: rs is NOT cleared each time */
5122 get_regionviews_by_id (*pr, rs);
5125 selection->set (rs);
5127 // first idle adds route children (automation tracks), so we need to redisplay here
5128 _routes->redisplay ();
5132 if (_session->undo_depth() == 0) {
5133 undo_action->set_sensitive(false);
5135 redo_action->set_sensitive(false);
5136 begin_selection_op_history ();
5142 Editor::_idle_resize (gpointer arg)
5144 return ((Editor*)arg)->idle_resize ();
5148 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5150 if (resize_idle_id < 0) {
5151 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5152 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5153 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5155 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5156 _pending_resize_amount = 0;
5159 /* make a note of the smallest resulting height, so that we can clamp the
5160 lower limit at TimeAxisView::hSmall */
5162 int32_t min_resulting = INT32_MAX;
5164 _pending_resize_amount += h;
5165 _pending_resize_view = view;
5167 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5169 if (selection->tracks.contains (_pending_resize_view)) {
5170 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5171 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5175 if (min_resulting < 0) {
5180 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5181 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5185 /** Handle pending resizing of tracks */
5187 Editor::idle_resize ()
5189 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5191 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5192 selection->tracks.contains (_pending_resize_view)) {
5194 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5195 if (*i != _pending_resize_view) {
5196 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5201 _pending_resize_amount = 0;
5202 _group_tabs->set_dirty ();
5203 resize_idle_id = -1;
5211 ENSURE_GUI_THREAD (*this, &Editor::located);
5214 playhead_cursor->set_position (_session->audible_frame ());
5215 if (_follow_playhead && !_pending_initial_locate) {
5216 reset_x_origin_to_follow_playhead ();
5220 _pending_locate_request = false;
5221 _pending_initial_locate = false;
5222 _last_update_time = 0;
5226 Editor::region_view_added (RegionView * rv)
5228 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5230 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5231 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5232 if (rv->region()->id () == (*rnote).first) {
5233 mrv->select_notes ((*rnote).second);
5234 selection->pending_midi_note_selection.erase(rnote);
5240 _summary->set_background_dirty ();
5244 Editor::region_view_removed ()
5246 _summary->set_background_dirty ();
5250 Editor::axis_view_from_stripable (boost::shared_ptr<Stripable> s) const
5252 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5253 if ((*j)->stripable() == s) {
5263 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5267 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5268 TimeAxisView* tv = axis_view_from_stripable (*i);
5278 Editor::suspend_route_redisplay ()
5281 _routes->suspend_redisplay();
5286 Editor::resume_route_redisplay ()
5289 _routes->redisplay(); // queue redisplay
5290 _routes->resume_redisplay();
5295 Editor::add_vcas (VCAList& vlist)
5299 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5300 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5303 add_stripables (sl);
5307 Editor::add_routes (RouteList& rlist)
5311 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5315 add_stripables (sl);
5319 Editor::add_stripables (StripableList& sl)
5321 list<TimeAxisView*> new_views;
5322 boost::shared_ptr<VCA> v;
5323 boost::shared_ptr<Route> r;
5324 TrackViewList new_selection;
5325 bool from_scratch = (track_views.size() == 0);
5327 sl.sort (StripablePresentationInfoSorter());
5329 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5331 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5333 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5335 new_views.push_back (vtv);
5337 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5339 if (r->is_auditioner() || r->is_monitor()) {
5343 RouteTimeAxisView* rtv;
5344 DataType dt = r->input()->default_type();
5346 if (dt == ARDOUR::DataType::AUDIO) {
5347 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5349 } else if (dt == ARDOUR::DataType::MIDI) {
5350 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5353 throw unknown_type();
5356 new_views.push_back (rtv);
5357 track_views.push_back (rtv);
5358 new_selection.push_back (rtv);
5360 rtv->effective_gain_display ();
5362 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5363 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5367 if (new_views.size() > 0) {
5368 _routes->time_axis_views_added (new_views);
5369 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5372 /* note: !new_selection.empty() means that we got some routes rather
5376 if (!from_scratch && !new_selection.empty()) {
5377 selection->set (new_selection);
5378 begin_selection_op_history();
5381 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5382 show_editor_mixer (true);
5385 editor_list_button.set_sensitive (true);
5389 Editor::timeaxisview_deleted (TimeAxisView *tv)
5391 if (tv == entered_track) {
5395 if (_session && _session->deletion_in_progress()) {
5396 /* the situation is under control */
5400 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5402 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5404 _routes->route_removed (tv);
5406 TimeAxisView::Children c = tv->get_child_list ();
5407 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5408 if (entered_track == i->get()) {
5413 /* remove it from the list of track views */
5415 TrackViewList::iterator i;
5417 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5418 i = track_views.erase (i);
5421 /* update whatever the current mixer strip is displaying, if revelant */
5423 boost::shared_ptr<Route> route;
5426 route = rtav->route ();
5429 if (current_mixer_strip && current_mixer_strip->route() == route) {
5431 TimeAxisView* next_tv;
5433 if (track_views.empty()) {
5435 } else if (i == track_views.end()) {
5436 next_tv = track_views.front();
5441 // skip VCAs (cannot be selected, n/a in editor-mixer)
5442 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5443 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5444 next_tv = track_views.front();
5446 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5447 /* just in case: no master, only a VCA remains */
5453 set_selected_mixer_strip (*next_tv);
5455 /* make the editor mixer strip go away setting the
5456 * button to inactive (which also unticks the menu option)
5459 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5465 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5470 if (apply_to_selection) {
5471 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5473 TrackSelection::iterator j = i;
5476 hide_track_in_display (*i, false);
5481 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5483 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5484 // this will hide the mixer strip
5485 set_selected_mixer_strip (*tv);
5488 _routes->hide_track_in_display (*tv);
5493 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5498 _routes->show_track_in_display (*tv);
5499 if (move_into_view) {
5500 ensure_time_axis_view_is_visible (*tv, false);
5505 Editor::sync_track_view_list_and_routes ()
5507 track_views = TrackViewList (_routes->views ());
5509 _summary->set_background_dirty();
5510 _group_tabs->set_dirty ();
5512 return false; // do not call again (until needed)
5516 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5518 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5523 /** Find a RouteTimeAxisView by the ID of its route */
5525 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5527 RouteTimeAxisView* v;
5529 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5530 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5531 if(v->route()->id() == id) {
5541 Editor::fit_route_group (RouteGroup *g)
5543 TrackViewList ts = axis_views_from_routes (g->route_list ());
5548 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5550 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5553 _session->cancel_audition ();
5557 if (_session->is_auditioning()) {
5558 _session->cancel_audition ();
5559 if (r == last_audition_region) {
5564 _session->audition_region (r);
5565 last_audition_region = r;
5570 Editor::hide_a_region (boost::shared_ptr<Region> r)
5572 r->set_hidden (true);
5576 Editor::show_a_region (boost::shared_ptr<Region> r)
5578 r->set_hidden (false);
5582 Editor::audition_region_from_region_list ()
5584 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5588 Editor::hide_region_from_region_list ()
5590 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5594 Editor::show_region_in_region_list ()
5596 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5600 Editor::step_edit_status_change (bool yn)
5603 start_step_editing ();
5605 stop_step_editing ();
5610 Editor::start_step_editing ()
5612 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5616 Editor::stop_step_editing ()
5618 step_edit_connection.disconnect ();
5622 Editor::check_step_edit ()
5624 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5625 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5627 mtv->check_step_edit ();
5631 return true; // do it again, till we stop
5635 Editor::scroll_press (Direction dir)
5637 ++_scroll_callbacks;
5639 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5640 /* delay the first auto-repeat */
5646 scroll_backward (1);
5654 scroll_up_one_track ();
5658 scroll_down_one_track ();
5662 /* do hacky auto-repeat */
5663 if (!_scroll_connection.connected ()) {
5665 _scroll_connection = Glib::signal_timeout().connect (
5666 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5669 _scroll_callbacks = 0;
5676 Editor::scroll_release ()
5678 _scroll_connection.disconnect ();
5681 /** Queue a change for the Editor viewport x origin to follow the playhead */
5683 Editor::reset_x_origin_to_follow_playhead ()
5685 framepos_t const frame = playhead_cursor->current_frame ();
5687 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5689 if (_session->transport_speed() < 0) {
5691 if (frame > (current_page_samples() / 2)) {
5692 center_screen (frame-(current_page_samples()/2));
5694 center_screen (current_page_samples()/2);
5701 if (frame < leftmost_frame) {
5703 if (_session->transport_rolling()) {
5704 /* rolling; end up with the playhead at the right of the page */
5705 l = frame - current_page_samples ();
5707 /* not rolling: end up with the playhead 1/4 of the way along the page */
5708 l = frame - current_page_samples() / 4;
5712 if (_session->transport_rolling()) {
5713 /* rolling: end up with the playhead on the left of the page */
5716 /* not rolling: end up with the playhead 3/4 of the way along the page */
5717 l = frame - 3 * current_page_samples() / 4;
5725 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5731 Editor::super_rapid_screen_update ()
5733 if (!_session || !_session->engine().running()) {
5737 /* METERING / MIXER STRIPS */
5739 /* update track meters, if required */
5740 if (contents().is_mapped() && meters_running) {
5741 RouteTimeAxisView* rtv;
5742 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5743 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5744 rtv->fast_update ();
5749 /* and any current mixer strip */
5750 if (current_mixer_strip) {
5751 current_mixer_strip->fast_update ();
5754 /* PLAYHEAD AND VIEWPORT */
5756 /* There are a few reasons why we might not update the playhead / viewport stuff:
5758 * 1. we don't update things when there's a pending locate request, otherwise
5759 * when the editor requests a locate there is a chance that this method
5760 * will move the playhead before the locate request is processed, causing
5762 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5763 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5765 if (_pending_locate_request || !_session->transport_rolling ()) {
5766 _last_update_time = 0;
5770 if (_dragging_playhead) {
5771 _last_update_time = 0;
5775 bool latent_locate = false;
5776 framepos_t frame = _session->audible_frame (&latent_locate);
5777 const int64_t now = g_get_monotonic_time ();
5780 if (_last_update_time > 0) {
5781 const double ds = (now - _last_update_time) * _session->transport_speed() * _session->nominal_frame_rate () * 1e-6;
5782 framepos_t guess = playhead_cursor->current_frame () + rint (ds);
5783 err = frame - guess;
5785 guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update)
5786 _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2
5789 printf ("eng: %ld gui:%ld (%+6.1f) diff: %6.1f (err: %7.2f)\n",
5791 err, _err_screen_engine);
5796 _err_screen_engine = 0;
5799 if (err > 8192 || latent_locate) {
5800 // in case of x-runs or freewheeling
5801 _last_update_time = 0;
5803 _last_update_time = now;
5806 if (playhead_cursor->current_frame () == frame) {
5810 playhead_cursor->set_position (frame);
5812 if (_session->requested_return_frame() >= 0) {
5813 _last_update_time = 0;
5817 if (!_follow_playhead || pending_visual_change.being_handled) {
5818 /* We only do this if we aren't already
5819 * handling a visual change (ie if
5820 * pending_visual_change.being_handled is
5821 * false) so that these requests don't stack
5822 * up there are too many of them to handle in
5828 if (!_stationary_playhead) {
5829 reset_x_origin_to_follow_playhead ();
5831 framepos_t const frame = playhead_cursor->current_frame ();
5832 double target = ((double)frame - (double)current_page_samples() / 2.0);
5833 if (target <= 0.0) {
5836 // compare to EditorCursor::set_position()
5837 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5838 double const new_pos = sample_to_pixel_unrounded (target);
5839 if (rint (new_pos) != rint (old_pos)) {
5840 reset_x_origin (pixel_to_sample (new_pos));
5847 Editor::session_going_away ()
5849 _have_idled = false;
5851 _session_connections.drop_connections ();
5853 super_rapid_screen_update_connection.disconnect ();
5855 selection->clear ();
5856 cut_buffer->clear ();
5858 clicked_regionview = 0;
5859 clicked_axisview = 0;
5860 clicked_routeview = 0;
5861 entered_regionview = 0;
5863 _last_update_time = 0;
5866 playhead_cursor->hide ();
5868 /* rip everything out of the list displays */
5872 _route_groups->clear ();
5874 /* do this first so that deleting a track doesn't reset cms to null
5875 and thus cause a leak.
5878 if (current_mixer_strip) {
5879 if (current_mixer_strip->get_parent() != 0) {
5880 global_hpacker.remove (*current_mixer_strip);
5882 delete current_mixer_strip;
5883 current_mixer_strip = 0;
5886 /* delete all trackviews */
5888 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5891 track_views.clear ();
5893 nudge_clock->set_session (0);
5895 editor_list_button.set_active(false);
5896 editor_list_button.set_sensitive(false);
5898 /* clear tempo/meter rulers */
5899 remove_metric_marks ();
5901 clear_marker_display ();
5903 stop_step_editing ();
5907 /* get rid of any existing editor mixer strip */
5909 WindowTitle title(Glib::get_application_name());
5910 title += _("Editor");
5912 own_window()->set_title (title.get_string());
5915 SessionHandlePtr::session_going_away ();
5919 Editor::trigger_script (int i)
5921 LuaInstance::instance()-> call_action (i);
5925 Editor::show_editor_list (bool yn)
5928 _editor_list_vbox.show ();
5930 _editor_list_vbox.hide ();
5935 Editor::change_region_layering_order (bool from_context_menu)
5937 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5939 if (!clicked_routeview) {
5940 if (layering_order_editor) {
5941 layering_order_editor->hide ();
5946 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5952 boost::shared_ptr<Playlist> pl = track->playlist();
5958 if (layering_order_editor == 0) {
5959 layering_order_editor = new RegionLayeringOrderEditor (*this);
5962 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5963 layering_order_editor->maybe_present ();
5967 Editor::update_region_layering_order_editor ()
5969 if (layering_order_editor && layering_order_editor->is_visible ()) {
5970 change_region_layering_order (true);
5975 Editor::setup_fade_images ()
5977 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5978 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5979 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5980 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5981 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5983 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5984 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5985 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5986 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5987 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5991 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5993 Editor::action_menu_item (std::string const & name)
5995 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5998 return *manage (a->create_menu_item ());
6002 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
6004 EventBox* b = manage (new EventBox);
6005 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
6006 Label* l = manage (new Label (name));
6010 _the_notebook.append_page (widget, *b);
6014 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6016 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6017 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6020 if (ev->type == GDK_2BUTTON_PRESS) {
6022 /* double-click on a notebook tab shrinks or expands the notebook */
6024 if (_notebook_shrunk) {
6025 if (pre_notebook_shrink_pane_width) {
6026 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6028 _notebook_shrunk = false;
6030 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6032 /* this expands the LHS of the edit pane to cover the notebook
6033 PAGE but leaves the tabs visible.
6035 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6036 _notebook_shrunk = true;
6044 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6046 using namespace Menu_Helpers;
6048 MenuList& items = _control_point_context_menu.items ();
6051 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6052 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6053 if (!can_remove_control_point (item)) {
6054 items.back().set_sensitive (false);
6057 _control_point_context_menu.popup (event->button.button, event->button.time);
6061 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6063 using namespace Menu_Helpers;
6065 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6070 /* We need to get the selection here and pass it to the operations, since
6071 popping up the menu will cause a region leave event which clears
6072 entered_regionview. */
6074 MidiRegionView& mrv = note->region_view();
6075 const RegionSelection rs = get_regions_from_selection_and_entered ();
6076 const uint32_t sel_size = mrv.selection_size ();
6078 MenuList& items = _note_context_menu.items();
6082 items.push_back(MenuElem(_("Delete"),
6083 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6086 items.push_back(MenuElem(_("Edit..."),
6087 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6088 if (sel_size != 1) {
6089 items.back().set_sensitive (false);
6092 items.push_back(MenuElem(_("Transpose..."),
6093 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6096 items.push_back(MenuElem(_("Legatize"),
6097 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6099 items.back().set_sensitive (false);
6102 items.push_back(MenuElem(_("Quantize..."),
6103 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6105 items.push_back(MenuElem(_("Remove Overlap"),
6106 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6108 items.back().set_sensitive (false);
6111 items.push_back(MenuElem(_("Transform..."),
6112 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6114 _note_context_menu.popup (event->button.button, event->button.time);
6118 Editor::zoom_vertical_modifier_released()
6120 _stepping_axis_view = 0;
6124 Editor::ui_parameter_changed (string parameter)
6126 if (parameter == "icon-set") {
6127 while (!_cursor_stack.empty()) {
6128 _cursor_stack.pop_back();
6130 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6131 _cursor_stack.push_back(_cursors->grabber);
6132 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6133 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6135 } else if (parameter == "draggable-playhead") {
6136 if (_verbose_cursor) {
6137 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6143 Editor::use_own_window (bool and_fill_it)
6145 bool new_window = !own_window();
6147 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6149 if (win && new_window) {
6150 win->set_name ("EditorWindow");
6152 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6154 // win->signal_realize().connect (*this, &Editor::on_realize);
6155 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6156 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6157 win->set_data ("ardour-bindings", bindings);
6162 DisplaySuspender ds;
6163 contents().show_all ();
6165 /* XXX: this is a bit unfortunate; it would probably
6166 be nicer if we could just call show () above rather
6167 than needing the show_all ()
6170 /* re-hide stuff if necessary */
6171 editor_list_button_toggled ();
6172 parameter_changed ("show-summary");
6173 parameter_changed ("show-group-tabs");
6174 parameter_changed ("show-zoom-tools");
6176 /* now reset all audio_time_axis heights, because widgets might need
6182 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6183 tv = (static_cast<TimeAxisView*>(*i));
6184 tv->reset_height ();
6187 if (current_mixer_strip) {
6188 current_mixer_strip->hide_things ();
6189 current_mixer_strip->parameter_changed ("mixer-element-visibility");